native代码想要访问 java虚拟机需要调用JNI方法,而获取JNI方法则通过 JNI interface Pointer。它实际指向的就是一个都是指针的数组,每个指针指向的都是一个接口函数
这样做的优势:
JNI interface Pointer 只在当前线程有效,即native 方法不能在线程之间传递(不同线程的指针可能不一 样),VM保证同一个线程中调用多次JNI interface Pointer是同一个
JAVA VM支持多线程,native 方法在编译的时候需要加上对应的参数,如 gcc加上 -D_REENTRANT或者-D_POSIX_C_SOURCE
代码如下
package pkg;
class Cls {
native double f(int i, String s);
static {
System.loadLibrary(“pkg_Cls”); //名字可以随便定义
}
}
复制代码
对于不同的系统,打包的后缀名会有不同,solaris系统一般是libpkg_Cls.so(使用的时候则是直接用的pkg_Cls)Win32的系统则是pkg_Cls.dll
如果当前系统不支持动态连接,所有的Native方法必须预先和VM建立连接,通过System.loadLibrary是无法自动加载。如果要静态连接可以使用 JNI的函数 RegisterNatives
静态连接需要把所有的library复制到可执行的映像中;动态连接是把共享的library的名字放在一个可执行的映像中,当映像运行的时候才去连接
方法签名的格式为:(形参参数类型列表)返回值
。
形参参数列表中,引用类型以L开头,后面紧跟类的全路径名(需将.全部替换成/),以分号结尾
比如:long f(int n,String s,int[] arr); 对应的Native方法签名是 (ILjava/lang/String;[I)J. 各种类型签名对比
第一个参数是JNI Interface pointer(类型是 JNIEnv),如果是静态native方法,第二个参数则是对应java class的引用,非静态的native则对应的是 对象的引用,其它的参数对应的是java方法的参数
public class HelloWorld {
public static native String sayHello(String name);
public static void main(String[] args) {
String text = sayHello("paxi");
System.out.println(text);
}
static{
System.loadLibrary("HelloWorld");
}
}
复制代码
javah -jni -d ./jni HelloWorld
;-d:将生成的文件放到jni目录下 生成结果如下:/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class HelloWorld */
#ifndef _Included_HelloWorld
#define _Included_HelloWorld
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: HelloWorld
* Method: sayHello
* Signature: (Ljava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_HelloWorld_sayHello
(JNIEnv *, jclass, jstring);
#ifdef __cplusplus
}
#endif
#endif
复制代码
HelloWorld.c:
#include "HelloWorld.h"
#ifdef __cplusplus
extern "C"
{
#endif
/*
* Class: HelloWorld
* Method: sayHello
* Signature: (Ljava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_HelloWorld_sayHello
(JNIEnv *env, jclass cls, jstring j_str){
const char *c_str = NULL;
char buff[128] = {0};
c_str = (*env)->GetStringUTFChars(env,j_str,NULL);
if (c_str == NULL)
{
printf("out of memory\n");
return NULL;
}
printf("Java Str:%s\n", c_str);
sprintf(buff,"hello %s",c_str);
(*env)->ReleaseStringUTFChars(env,j_str,c_str);
return (*env)->NewStringUTF(env,buff);
}
#ifdef __cplusplus
}
#endif
复制代码
gcc -dynamiclib -o extensions/libHelloWorld.jnilib jni/HelloWorld.c -framework JavaVM -I/Library/Java/JavaVirtualMachines/jdk1.7.0_79.jdk/Contents/Home/include -I/Library/Java/JavaVirtualMachines/jdk1.7.0_79.jdk/Contents/Home/include/darwin
* -dynamiclib:表示生成动态链接库
* -o:指定动态链接库编译后生成的路径以及文件名
* -framwork JavaVM -I:编译JNI需要用到的JVM头文件(jni.h)
复制代码
java -Djava.library.path=动态链接的目录 Helloworld
java Str:paxi
hello paxi
复制代码
JNI 文档 JNI hello world原博客地址