Eclipse添加一键调用javah生成jni的头文件:
Run->External Tools External Tools Configurations->Program->New launch configuration ,填写:
Location:${system_path:javah}
Working Directory:${project_loc}\src
Arguments:(javah命令)-classpath .;./classes -d “ projectloc"−jni {java_type_name}
.;./classes为class文件目录
-d “${project_loc}”为生成.h文件存放位置
如要javah文件改变立刻刷新,则:
Comman->DisPlay in favorite menu,勾上
选中要转化的java文件:
Run->External Tools->Generate c and c++ Header File
在项目目录下会发现生成了.h的头文件
JNIEnv:一个指向java类可用函数表的指针,java对象引用类实例
public native String stringFromJNI();
方法依赖于类的实例,传入类的实例thiz作为第二个参数,对应的头文件:
JNIEXPORT jstring JNICALL Java_com_example_hellojni_HelloJni_stringFromJNI
(JNIEnv * env, jobject thiz);
public static native String stringFromJNI();
静态方法不依赖于类的实例,传入类的Class作为第二个参数,对应的头文件:
JNIEXPORT jstring JNICALL Java_com_example_hellojni_HelloJni_stringFromJNI
(JNIEnv * env, jclass clazz);
基本数据类型boolean, byte, char, short, int, long, float,double
引用数据类型String, arrays, 其它
String操作:
string为引用类型,string对象不可改变,jni转换为c字符串,支持Unicode 和 UTF-8两套编码通过JNIEnv的接口指针来处理。
GetStringUTFChars将jstring转换成为UTF-8格式的char*
GetStringChars将jstring转换成为Unicode格式的char*
ReleaseStringUTFChars释放指向UTF-8格式的char*的指针
ReleaseStringChars释放指向Unicode格式的char*的指针
NewStringUTF创建一个UTF-8格式的String对象
NewString创建一个Unicode格式的String对象
GetStringUTFLengt获取 UTF-8格式的char*的长度
GetStringLength获取Unicode格式的char*的长 度
Array
jintArray javaArray;
javaArray = (*env)->NewIntArray(env, 10);
if (0 != javaArray) {
/* You can now use the array. */
}
复制到缓冲区修改array
jint nativeArray[10];
(*env)->GetIntArrayRegion(env, javaArray, 0, 10, nativeArray);
返回修改结果
(*env)->SetIntArrayRegion(env, javaArray, 0, 10, nativeArray);
当数组过大,复制导致性能问题,则提供获得一个数组元素直接指针
jint* nativeDirectArray;
jboolean isCopy;
nativeDirectArray = (*env)->GetIntArrayElements(env, javaArray, &isCopy);
(*env)->ReleaseIntArrayElements(env, javaArray, nativeDirectArray, 0);
0:返回内容,并释放本地array
JNI_COMMIT:返回内容不释放,用于周期性更新
JNI_ABORT:释放array并不复制
isCopy参数传入的是一个jboolean的指针,其值可以为NULL、JNI_TRUE、JNI_FLASE。
如果为JNI_TRUE则表示在本地开辟内存,然后把Java中的String拷贝到这个内存中,然后返回指向这个内存地址的指针。如果为JNI_FALSE,则直接返回指向Java中String的内存指针。这时不要改变这个内存中的内容,这将破坏String在Java中始终是常量的规则。
如果是NULL,则表示不关心是否拷贝字符串。
根据给定的Ç字节数组创建新的字节缓冲区,需要释放
unsigned char* buffer = (unsigned char*) malloc(1024);
...
jobject directBuffer;
directBuffer = (*env)->NewDirectByteBuffer(env, buffer, 1024);
直接字节缓冲区,也可以在Java应用程序中创建。本机代码可以使用
GetDirectBufferAddress函数调用来获取本地字节数组的内存地址,
unsigned char* buffer;
buffer = (unsigned char*) (*env)->GetDirectBufferAddress(env,
directBuffer);
一个包含私有静态和变量的实例类
public class JavaClass {
/** Instance field */
private String instanceField = "Instance Field";
/** Static field */
private static String staticField = "Static Field";
...
}
获取从类对象引用
jclass clazz;
clazz = (*env)->GetObjectClass(env, instance);
获取一个实例字段的字段标识
jfieldID instanceFieldId;
instanceFieldId = (*env)->GetFieldID(env, clazz,
"instanceField", "Ljava/lang/String;");
获取静态字段的字段标识
jfieldID staticFieldId;
staticFieldId = (*env)->GetStaticFieldID(env, clazz,
"staticField", "Ljava/lang/String;");
获取静态字段
jstring staticField;
staticField = (*env)->GetStaticObjectField(env, clazz, staticFieldId);
获取JAVA签名:
javap –classpath bin/classes –p –s com.example.hellojni.HelloJni
创建指向某个对象的局部引用,创建失败返回NULL
jobject NewLocalRef(jobject ref);
删除局部引用
void DeleteLocalRef(jobject obj);
创建指向某个对象的全局引用,创建失败返回NULL
jobject NewGlobalRef(jobject lobj);
删除全局引用
void DeleteGlobalRef(jobject gref);
jclass localClazz;
jclass globalClazz;
...
localClazz = (*env)->FindClass(env, "java/lang/String");
globalClazz = (*env)->NewGlobalRef(env, localClazz);
...
(*env)->DeleteLocalRef(env, localClazz);
(*env)->DeleteGlobalRef(env, globalClazz);
弱全局对象,可被垃圾回收期回收
jclass weakGlobalClazz;
weakGlobalClazz = (*env)->NewWeakGlobalRef(env, localClazz);
(*env)->DeleteWeakGlobalRef(env, weakGlobalClazz);
检查是否被回收
if (JNI_FALSE == (*env)->IsSameObject(env, weakGlobalClazz, NULL)) {
/* Object is still live and can be used. */
} else {
/* Object is garbage collected and cannot be used. */
}
局部引用Local 不能多线程共享,只有全局引用global才行,JNIEnv接口指针只在相关线程有效,不能缓存和用于其它线程
Java的同步代码块
synchronized(obj) {
/* Synchronized thread-safe code block. */
}
native实现
if (JNI_OK == (*env)->MonitorEnter(env, obj)) {
/* Error handling. */
}
/* Synchronized thread-safe code block. */
if (JNI_OK == (*env)->MonitorExit(env, obj)) {
/* Error handling. */
}
为防止死锁,MonitorEnter应与MonitorExit匹配
在当前虚拟机中创建和停止线程
JavaVM* cachedJvm;
...
JNIEnv* env;
...
(*cachedJvm)->AttachCurrentThread(cachedJvm, &env, NULL);
(*cachedJvm)->DetachCurrentThread(cachedJvm);
http://docs.oracle.com/javase/1.5.0/docs/guide/jni/