数组处理的一些细节
首先我们写java代码交给c语言对数组进行排序
public static void main(String[] args) {
//数组处理的一些细节
int[] arr={11,22,3,-5,4,9,-15};
sort(arr);
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]+"\t");
}
}
生成头文件,并将头文件和jni.h,jni_md.h两个文件拷贝到新建的vs项目中的相关目录下
c语言实现数组排序代码
#include "com_example_demo_test.h"
#include<stdio.h>
#include<stdlib.h>
int compare(const int *number1, const int*number2){
return *number1 - *number2;
}
JNIEXPORT void JNICALL Java_com_example_demo_test_sort
(JNIEnv *env, jclass clazz, jintArray jarray){
//对jarray进行排序
//第一个参数:void* 数组的首地址
jint* intArray=(*env)->GetIntArrayElements(env, jarray, NULL);
//第二个参数 num 是 参与排序的目标数组元素个数
int length = (*env)->GetArrayLength(env, jarray);
//第三个参数 数组元素数据类型的大小
//第四个参数,数组的一个方法比较指针
qsort(intArray, length, sizeof(int), compare);
//同步数组的数据给java数组,intArray并不是jarray,可以理解为简单的copy
//0:既要同步数据给jarray,又要释放intArray
//JNI_COMMIT:会同步数据给jArray,且会释放intArray
//JNI_ABORT:不同步数据给jArray,但是会释放intArray
(*env)->ReleaseIntArrayElements(env, jarray, intArray, JNI_ABORT);
}
生成相应的dll库,具体方法大家可以参考我这篇:JNI 基础 – JNIEnv 的实现原理https://www.jianshu.com/p/d4a502420a89
java代码中引入动态库
static {
System.load("D:/visual studio 2013/Projects/jni/x64/Debug/jni.dll");
}
}
局部引用和全局引用
局部引用,java代码
private static native void localRef();
c代码
JNIEXPORT void JNICALL Java_com_example_demo_test_localRef
(JNIEnv *env, jclass jclz){
//字符串截取,String对象
jclass str_clz = (*env)->FindClass(env, "java/lang/String");
//构造函数
jmethodID init_mid = (*env)->GetMethodID(env, str_clz, "<init>", "()V");
jobject j_str = (*env)->NewObject(env, str_clz, init_mid);
//jobject不要再使用了,要回收
(*env)->DeleteLocalRef(env, j_str);
//删除后就不能再使用,c和c++都需要自己去释放内存(静态开辟不需要,动态开辟的需要)
}
全局引用java代码
//局部引用和全局引用
public static void main(String[] args) {
//局部引用和全局引用
//localRef();
savelobalRef("Peakmain");
System.out.println(getGlobalRef());
//合适的时机去释放
deleteGlobalRef();
//再次获取,此时会报空指针异常错误
System.out.println(getGlobalRef());
}
private static native void savelobalRef(String name);
private static native String getGlobalRef();
private static native void deleteGlobalRef();
c代码的实现
//全局变量
jstring globalStr;
//保存全局变量
JNIEXPORT void JNICALL Java_com_example_demo_test_savelobalRef
(JNIEnv *env, jclass jcls, jstring str) {
//保存全局变量,其他方法需要到
globalStr = (*env)->NewGlobalRef(env, str);
}
//获得全局变量
JNIEXPORT jstring JNICALL Java_com_example_demo_test_getGlobalRef
(JNIEnv *env, jclass jclz){
return globalStr;
}
//删除全局变量
JNIEXPORT jstring JNICALL Java_com_example_demo_test_deleteGlobalRef
(JNIEnv *env, jclass jclz) {
(*env)->DeleteGlobalRef(env, globalStr);
}
静态缓存策略
局部缓存策略
java代码
private static String name;
public static void main(String[] args) {
//3.缓存策略 static,native中有一大堆方法要去获取name属性
staticLocalCache("Peakmain");
System.out.println("name="+name);
staticLocalCache("Treasure");
System.out.println("name="+name);
staticLocalCache("Body");
System.out.println("name="+name);
}
private static native void staticLocalCache(String name);
c代码的实现
JNIEXPORT void JNICALL Java_com_example_demo_test_staticLocalCache
(JNIEnv *env, jclass jclz, jstring name) {
//name属性赋值
static jfieldID j_fid = NULL;//加了一个局部缓存,如果这个方法会被多次调用,我们不需要反复去获取jfieldID
if (j_fid == NULL) {
j_fid = (*env)->GetStaticFieldID(env, jclz, "name", "Ljava/lang/String;");
}
else {
printf("field is not NULL\n");
}
(*env)->SetStaticObjectField(env, jclz, j_fid, name);
}
全局缓存策略
java代码
//初始化全局静态缓存
private static native void initStaticCache();
c代码的实现
//全局静态缓存,在构造函数初始化的时候
static jfieldID j_fid1 = NULL;
static jfieldID j_fid2 = NULL;
static jfieldID j_fid3 = NULL;
JNIEXPORT jstring JNICALL Java_com_example_demo_test_initStaticCache
(JNIEnv *env, jclass jclz){
//初始化全局静态缓存
j_fid1 = (*env)->GetStaticFieldID(env, jclz, "name", "Ljava/lang/String;");
j_fid2 = (*env)->GetStaticFieldID(env, jclz, "name1", "Ljava/lang/String;");
j_fid3 = (*env)->GetStaticFieldID(env, jclz, "name2", "Ljava/lang/String;");
}
JNIEXPORT void JNICALL Java_com_example_demo_test_staticLocalCache
(JNIEnv *env, jclass jclz, jstring name) {
//如果这个方法反复被调用,那么不会反复获取name属性
(*env)->SetStaticObjectField(env, jclz, j_fid1, name);
(*env)->SetStaticObjectField(env, jclz, j_fid2, name);
(*env)->SetStaticObjectField(env, jclz, j_fid3, name);
}
jni异常处理
java代码
public static void main(String[] args) {
//异常处理
try {
exception();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
System.out.println("name = " + name3);
}
private static native void exception() throws NoSuchFieldException;
c代码的实现
JNIEXPORT void JNICALL Java_com_example_demo_test_exception
(JNIEnv *env, jclass jclz) {
//假设现在想给name进行赋值,但是现在拿没有的name3
jfieldID j_fid= (*env)->GetStaticFieldID(env, jclz, "name3", "Ljava/lang/String;");
jstring name=(*env)->NewStringUTF(env,"Peakmain");//这时候会抛异常
//解决办法
//1.补救措施,name3没有拿name
//1.1判断有没有异常
jthrowable throwable=(*env)->ExceptionOccurred(env);
/* if(throwable){
//补救措施
printf("有异常");
//先把异常清除一下
(*env)->ExceptionClear(env);
//重新获取name属性
j_fid= (*env)->GetStaticFieldID(env, jclz, "name", "Ljava/lang/String;");
}*/
//2.给java层抛一个异常
if(throwable){
//补救措施
printf("有异常");
//先把异常清除一下
(*env)->ExceptionClear(env);
//抛出一个java异常Throwable对象
jclass no_such_clz=(*env)->FindClass(env,"java/lang/NoSuchFieldException");
(*env)->ThrowNew(env, no_such_clz,"NoSuchFieldException name3");
return ;//记得return
}
(*env)->SetStaticObjectField(env, jclz, j_fid, name);
}
native出错了没办法在java层try,处理方式一般两种,一个是补救,一个是构建java异常对象向上抛