Java中調用Windows平臺的動態庫一般會使用JNI(Java Native Interface)還有JNA(Java Native Access)。
首先解釋下爲什麼我會選用JNA,一句話來說就是使用簡單。
我們知道,使用JNI調用.dll/.so共享類庫是非常非常麻煩和痛苦的。 如果有一個現有的.dll/.so文件,如果使用JNI技術調用,我們首先需要另外使用C語言寫一個.dll/.so共享庫,使用SUN規定的數據結構替代C語言的數據結構,調用已有的 dll/so中公佈的函數。然後再在Java中載入這個適配器dll/so,再編寫Java native函數作爲dll中函數的代理。
經過2個繁瑣的步驟才能在Java中調用本地代碼。因此,很少有Java程序員願意編寫調用dll/.so庫中的原生函數的java程序。這也使Java語言在客戶端上乏善可陳。可以說JNI是Java的一大弱點!所以我們就選擇JNA來寫幾個簡單的demo。
JNA在GitHub上的地址:https://github.com/twall/jna
需要jar包,到lib文件夾裏面去下載。
第一個例子:
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Platform;
public class HelloWorld {
public interface CLibrary extends Library {
CLibrary INSTANCE = (CLibrary) Native.loadLibrary((Platform.isWindows() ? "msvcrt" : "c"), CLibrary.class);
void printf(String format, Object... args);
}
public static void main(String[] args) {
CLibrary.INSTANCE.printf("Hello World, ");
for (int i = 0; i < args.length; i++) {
CLibrary.INSTANCE.printf("Argument %d: %s, ", i, args[i]);
}
}
}
運行上面的代碼,我給main函數傳遞了3個參數1 2 3,打印如下:
Hello World, Argument 0: 1, Argument 1: 2, Argument 2: 3,
但是,請注意,這個程序實際上是使用msvcrt.dll這個C運行時庫中的printf函數打印出上面這些字符的。是不是很簡單,不需要寫一行C代碼,就可以直接在Java中調用外部動態鏈接庫中的函數!
第二個例子:
上面那個例子使用了操作系統自帶的動態鏈接庫,現在我們再自己寫一個動態鏈接庫試試。
1,在VS中選擇C++語言,然後選擇創建一個Win32程序。選擇dll類型。
2,發佈的C函數是:
#define MYLIBAPI extern "C" __declspec(dllexport )
MYLIBAPIvoid say(wchar_t* pValue);
這個函數的實現是:
void say(wchar_t* pValue){
std::wcout.imbue(std::locale("chs"));
std::wcout<<L"他說:"<<pValue<<std::endl;
}
它需要傳入一個Unicode編碼的字符數組。然後在控制檯上打印出一段中文字符。
3,生成dll(TestDll1.dll)。然後把生成的dll文件複製到Eclipse項目中,放在項目下面。
4,然後編寫下面的類:
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.WString;
public class TestDll1Service {
public interface TestDll1 extends Library {
/**
* 當前路徑是在項目下,而不是bin輸出目錄下。
*/
TestDll1 INSTANCE = (TestDll1)Native.loadLibrary("TestDll1", TestDll1.class);
public void say(WString value);
}
public TestDll1Service() {
}
/**
* @param args
*/
public static void main(String[] args) {
TestDll1.INSTANCE.say(new WString("Hello World!"));
System.out.println("你好,我是來測試的!");
}
}
5,執行這個Java類。可以看到控制檯下如下輸出:
他說: Hello World!
你好,我是來測試的!
6,上面一行是C語言使用C++的std::wcout輸出的。 下面一行是Java語言輸出的。