1、访问构造方法
jclass cls = (*env)->FindClass(env,"java/util/Date"); jmethodID constructor_mid = env->GetMethodID(env,cls,"<init>","()V"); jobject date_obj = env->NewObject(env,cls,constructor_mid); <!-- 通知垃圾回收期回收对象 --> (*env)->DeleteLocalRef(env,data_obj);
2、访问父类的构造方法
char* c_str = "迪丽热巴"; jclass str_cls = (*env)->FindClass(env,"Ljava/langString;"); jmethodID constructor_mid = (*env)->GetMethodID(env,str_cls,"<init>","([BLjava/lang/String;])V") <!-- 第一个参数 --> <!-- jbyte -> char --> jbyteArray bytes = (*env)->NewByteArray(env,strlen(c_str)); <!-- byte 数组赋值 --> (*env)->SetByteArrayRegion(env,bytes,0,strlen(c_str),c_str); <!-- 第二个参数 --> jstring charsetName = (*env)->NewStringUTF(env,"GB2312"); return (*env)->NewObject(env,str_cls,constructor_mid,bytes,charsetName);
3、数组处理_JNI引用 数组排序 int[] arr
1、函数指针:
#include <stdlib.h> int compare(const void* a,const void* b){ return (*a) -(*b); } <!-- 对java传递过来的数组进行排序 --> <!-- NULL 操作的是同一块内存 : 第三个参数是一个jboolean类型的指针,如果被赋值为1,表示内部进行了拷贝,为零表示内部没有拷贝,是同一块内存。程序员无法控制这个变量 --> jint * elems = (*eng)->GetIntArrayElements(env,arr,NULL); <!-- 数组的长度,env --> int len = (*eng)->GetArrayLength(env,arr); <!-- 函数指针 --> <!-- 排序 --> qsort(elems,len,sizeof(jint),compare); <!-- jni 数据同步 --> <!-- 第四个参数 mode 0,java数组进行更新,并且释放C/C++数组 JNI_ABORT,java 数组不进行更新,但是释放C/C++数组 JNI_COMMIT,java数组进行更新,不释放C/C++数组(函数运行完,数组还是要释放的) --> (*env)->ReleaseIntArrayElements(env,arr,elems,0);
2、返回一个int类型的数组
jintArray jint_arr = (*env)->NewInntArray(env,len) jint* elems = (*env)->GetIntArrayElements(env,jint_arr,NULL); for(int i=0;i<len;++i){ elems[i] = i; } (*env)->ReleaseIntArrayElements(env,jint_arr,elems,0); return jint_arr;
3、局部引用和全局引用
1、局部引用,通过DeleteLocalRef手动释放对象
#1、访问一个很大的java对象,使用完之后,还要进行复杂的耗时操作
#2、创建了大量的局部引用,占用了太多的内存,而且这些局部引用跟后面的操作没有关联。
2、全局引用,多个方法里面都可以引用
<!-- 解决数据共享问题(可以跨多个线程),手动控制内存的使用 -->
<!-- 自己处理线程安全问题 -->
jstring global_str; void createGlobalRef(){ jstring obj = (*env)->NewStringUTF(env,"jni is powerful"); global_str = (*env)->NewGlobalRef(obj); } void getGlobalRef(){ return global_str; } void deleteGlobalRef(){ (*env)->DeleteGlobalRef(global_str); }
<!-- java 方法 --> class JniTest{ public native void createGlobalRef(); public native void getGlobalRef(); public native void deleteGlobalRef(); public static void main(String[] args){ JniTest t = new JniTest(); t.createGlobalRef(); t.getGlobalRef(); t.deleteGlobalRef(); t.getGlobalRef(); } }
3、弱全局引用
<!-- 节省内存,在内存不足时可以是释放所引用的对象 -->
<!-- 可以引用一个不常用的对象,如果为NULL,临时创建 -->
<!-- 创建: NewWeakGlobalRef,销毁 DeleteGlboalWeakRef -->
4、异常处理 (Native 异常,无法在Java层catch) 只能在native 层处理
<!--1、 保证java代码可以运行 --> <!--2、 确保补救措施,保证C代码继续运行--> <!--JNI 自己抛出的异常,在Java层无法被捕捉,只能在C层清空--> <!--用户自己抛出的异常,可以在Java层处理 --> void exception(JNIEnv* env,jobject obj){ jclass cls = (*env)->GetObjectClass(env,obj); jfieldId fid = (*env)->GetFieldID(env,cls,"key2","Ljava/lang/String;"); <!-- 检测是否发生Java异常 --> jthrowable exception = (*env)->ExceptionOccurred(env); if(exception != null){ <!-- 让Java 代码可以继续执行 --> <!-- 清空异常信息 --> (*env)->ExceptionClear(env); <!-- 补救措施 --> <!-- 获取第二个属性 确保必须可以得到--> fid = (*env)->GetFieldID(env,cls,"key","Ljava/lang/String;"); } jstring jstr = (*env)->GetObjectField(env,jobj,fid); char * str = (*env)->GetStringUTFChars(env,jstr,NULL); <!-- 对比属性值是否合法 --> if(stricmp(str,"super jason1") != 0){ <!-- 认为抛出异常,给Java层处理 --> jclass newExeCls = (*env)->FindClass(env,"Ljava/lang/IllegalArgumentException;"); (*env)->ThrowNew(env,newExeCls,"Key's value is invalid!"); } }
java 代码
t.exception();
4、缓存策略
1、使用局部静态变量
<!-- 在Java层循环调用很多次 一个native方法 --> void cached(JNIEnv* env,jobject obj){ jclass cls = (*env)->GetObjectClass(env,obj); <!-- 获取fid 只获取一次 --> <!-- 局部静态变量 ; --> static jfieldID = key_id = null; if(key_id == null){ key_id = (*env)->GetFieldID(env,cls,"key","Ljava/lang/String;"); print("==========GetFieldID=========="); } }
2、initIDs(),
<!-- 在C层后面使用的对象在一个方法里面初始化,initIDs()在加载库的时候调用。 -->
java
public static void initIDs(); static { System.load("lib"); initIDs(); }
C :
jfieldID key_fid; initIds(JNIEnv* env,jclass jcls){ <!-- jclass cls = (*env)->GetObjectClass(env,obj); --> key_fid = (*env)->GetFieldID(env,jcls,"key","Ljava/lang/String;"); }