Java 調(diào)用底層接口
Java 調(diào)用底層接口要通過動態(tài)鏈接庫進行,在windows下是dll文件,linux是so文件
Java調(diào)用動態(tài)庫所需要關心的問題:
·
如何裝載文件,以及如何定位所要使用的方法;
·
數(shù)據(jù)類型是如何對應的;
·
如何給使用的方法傳遞參數(shù);
·
如何獲取返回的值。
目前調(diào)用底層接口用的比較多的技術包括jni、jna、jnative、Nativecall等
JNI 封裝本地接口
JAVA可以通過JNI接口訪問本地的動態(tài)連接庫,從而擴展JAVA的功能。使用JAVA JNI接口主要包括以下步驟:
2 編寫JAVA代碼,注明要訪問的本地動態(tài)連接庫和本地方法;
2 編譯JAVA代碼得到.class文件;
2 使用javah -jni 生成該類對應的C語言.h文件;
2 使用C/C++實現(xiàn)(3)生成的.h文件中聲明的各函數(shù);
2 編譯C/C++實現(xiàn)代碼生成動態(tài)連接庫。
本文使用一個簡單的helloWorld示例演示JNI的使用。
編寫JAVA代碼
View Code
1 public class helloWorld
2
3 {
4
5 public native void SayHello(String name);
6
7
8
9 static
10
11 {
12
13 System.loadLibrary("jniHelloworld");
14
15 }
16
17
18
19 public static void main(String [] argv)
20
21 {
22
23 helloWorld
hello = new helloWorld();
24
25 hello.SayHello("world ");
26
27 }
28 }
編譯JAVA代碼
javac helloWorld.java
生成實現(xiàn)函數(shù)頭文件
javah -classpath . helloWorld
得到的helloWorld.h文件內(nèi)容如下:
View Code
1 /* DO NOT EDIT THIS FILE - it is machine generated */
2
3 #include
<jni.h>
4
5 /* Header for class helloWorld */
6
7
8
9 #ifndef
_Included_helloWorld
10
11 #define
_Included_helloWorld
12
13 #ifdef __cplusplus
14
15 extern "C" {
16
17 #endif
18
19 /*
20
21 * Class: helloWorld
22
23 * Method: SayHello
24
25 * Signature:
(Ljava/lang/String;)V
26
27 */
28
29 JNIEXPORT void JNICALL
Java_helloWorld_SayHello
30
31 (JNIEnv *,
jobject, jstring);
32
33
34
35 #ifdef __cplusplus
36
37 }
38
39 #endif
40
41 #endif
在VS中創(chuàng)建工程并實現(xiàn)該函數(shù)
View Code
1 #include "helloWorld.h"
2
3 #include
<stdio.h>
4
5 #include <string.h>
6
7 void JNICALL Java_helloWorld_SayHello(JNIEnv *
env, jobject obj, jstring str)
8
9 {
10
11 jboolean b = true;
12
13 char s[80];
14
15 memset(s, 0, sizeof(s));
16
17 strcpy_s(s ,(char*)env->GetStringUTFChars(str, &b));
18
19 printf("Hello, %s", s);
20
21 env->ReleaseStringUTFChars(str , NULL);
22
23 }
這是JNI的關鍵:通過env我們可以使用JAVA提供的一組函數(shù)操作與轉(zhuǎn)換函數(shù)傳遞的參數(shù)。
編譯VC項目得到動態(tài)連接庫 helloWorld.dll。
把工程輸出文件的位置設置成helloWorld類所在的目錄,編譯之前要把jdk的include目錄加到工程屬性中
然后在命令行中執(zhí)行
Java helloWorld 會輸出helloWorld
JNA封裝本地接口
http://jna./#demos
View Code
1 package com.sun.jna.examples;
2
3
4
5 import
com.sun.jna.Library;
6
7 import
com.sun.jna.Native;
8
9 import
com.sun.jna.Platform;
10
11
12
13 /** Simple example of JNA interface mapping and usage. */
14
15 public class HelloWorld {
16
17
18
19 // This is the standard, stable way of
mapping, which supports extensive
20
21 //
customization and mapping of Java to native types.
22
23 public interface CLibrary extends Library {
24
25 CLibrary
INSTANCE = (CLibrary)
26
27 Native.loadLibrary((Platform.isWindows()
? "msvcrt" : "c"),
28
29 CLibrary.class);
30
31
32
33 void printf(String format, Object... args);
34
35 }
36
37
38
39 public static void main(String[] args) {
40
41 CLibrary.INSTANCE.printf("Hello, World\n");
42
43 for (int i=0;i < args.length;i++) {
44
45 CLibrary.INSTANCE.printf("Argument %d: %s\n", i, args[i]);
46
47 }
48
49 }
50
51 }
JNA 可以直接調(diào)用底層接口,而不用對底層接口進行封裝,像例子調(diào)用printf一樣,底層接口可以通過這種方式直接把接口提供給java調(diào)用
Jnative
Jnative用法和jna類似,都是借助于開源項目實現(xiàn)對底層接口的調(diào)用,但是用法比jna簡單一點,不需要在一個java接口中描述目標文件中的函數(shù)與結(jié)構(gòu),用法如下:
建立test_say.java文件,需要配置好JNative.jar包
View Code
1 import org.xvolks.jnative.JNative;
2
3 import org.xvolks.jnative.Type;
4
5 import
org.xvolks.jnative.exceptions.NativeException;
6
7 import org.xvolks.jnative.pointers.Pointer;
8
9 import
org.xvolks.jnative.pointers.memory.MemoryBlockFactory;
10
11 import org.xvolks.jnative.pointers.memory.NativeMemoryBlock;
12
13 import org.xvolks.jnative.util.Callback;
14
15 //import org.xvolks.test.callbacks.linux.LinuxCallback;
16
17
18
19 public class test_ helloWorld {
20
21 private final static String LIB_NAME = " msvcrt
"; //自動判斷.so 或者.dll
22
23
24
25 public static void main(String[] args) throws NativeException, IllegalAccessException {
26
27 try {
28
29 JNative
printf =new JNative(LIB_NAME," printf ");
30
31 printf.setParameter(0,”hello
world”);
32
33 printf.invoke();
34
35 }
36
37 catch (Exception e)
38
39 {
40
41 e.printStackTrace();
42
43 }
44
45 }
46
47 }
|