首页 文章 精选 留言 我的

精选列表

搜索[网站开发],共10000篇文章
优秀的个人博客,低调大师

02.Jni开发流程_C/C++调用java

(创建于2017/11/18) c/c++调用Java包括几个分类,调用Java静态和非静态属性,静态和非静态方法四种 提示: 生成一个类中所有属性成员签名的方法如下: 1.进入这个类class文件所在的路径:如JniUtils这个类在d盘下 D:\application\java\eclipse-workspace\TestJni\bin\com\renzhenming\bsdiff> 2.执行命令D:\application\java\eclipse-workspace\TestJni\bin\com\renzhenming\bsdiff>javap -p -s JniUtils 3.会得到结果:descriptor所对应的就是签名 Compiled from "JniUtils.java" public class com.renzhenming.bsdiff.JniUtils { public static int key; descriptor: I static {}; descriptor: ()V public com.renzhenming.bsdiff.JniUtils(); descriptor: ()V public native void changeIntKey(); descriptor: ()V public native void accessMethod(); descriptor: ()V public native void accessStaticMethod(); descriptor: ()V public int getRandomInt(int); descriptor: (I)I public static java.lang.String getUUId(); descriptor: ()Ljava/lang/String; } 生成系统类签名的方法,以java.util.Date为例 直接进入命令行,输入javap -s -p 完整类名 C:\Users\renzhenming>javap -s -p java.util.Date Compiled from "Date.java" public class java.util.Date implements java.io.Serializable, java.lang.Cloneable, java.lang.Comparable<java.util.Date> { private static final sun.util.calendar.BaseCalendar gcal; descriptor: Lsun/util/calendar/BaseCalendar; private static sun.util.calendar.BaseCalendar jcal; descriptor: Lsun/util/calendar/BaseCalendar; private transient long fastTime; descriptor: J private transient sun.util.calendar.BaseCalendar$Date cdate; descriptor: Lsun/util/calendar/BaseCalendar$Date; private static int defaultCenturyStart; descriptor: I private static final long serialVersionUID; descriptor: J private static final java.lang.String[] wtb; descriptor: [Ljava/lang/String; private static final int[] ttb; descriptor: [I public java.util.Date(); descriptor: ()V public java.util.Date(long); descriptor: (J)V public java.util.Date(int, int, int); descriptor: (III)V public java.util.Date(int, int, int, int, int); descriptor: (IIIII)V public java.util.Date(int, int, int, int, int, int); descriptor: (IIIIII)V public java.util.Date(java.lang.String); descriptor: (Ljava/lang/String;)V public java.lang.Object clone(); descriptor: ()Ljava/lang/Object; public static long UTC(int, int, int, int, int, int); descriptor: (IIIIII)J public static long parse(java.lang.String); descriptor: (Ljava/lang/String;)J public int getYear(); descriptor: ()I public void setYear(int); descriptor: (I)V public int getMonth(); descriptor: ()I public void setMonth(int); descriptor: (I)V public int getDate(); descriptor: ()I public void setDate(int); descriptor: (I)V public int getDay(); descriptor: ()I public int getHours(); descriptor: ()I public void setHours(int); descriptor: (I)V public int getMinutes(); descriptor: ()I public void setMinutes(int); descriptor: (I)V public int getSeconds(); descriptor: ()I public void setSeconds(int); descriptor: (I)V public long getTime(); descriptor: ()J private final long getTimeImpl(); descriptor: ()J public void setTime(long); descriptor: (J)V public boolean before(java.util.Date); descriptor: (Ljava/util/Date;)Z public boolean after(java.util.Date); descriptor: (Ljava/util/Date;)Z public boolean equals(java.lang.Object); descriptor: (Ljava/lang/Object;)Z static final long getMillisOf(java.util.Date); descriptor: (Ljava/util/Date;)J public int compareTo(java.util.Date); descriptor: (Ljava/util/Date;)I public int hashCode(); descriptor: ()I public java.lang.String toString(); descriptor: ()Ljava/lang/String; private static final java.lang.StringBuilder convertToAbbr(java.lang.StringBuilder, java.lang.String); descriptor: (Ljava/lang/StringBuilder;Ljava/lang/String;)Ljava/lang/StringBuilder; public java.lang.String toLocaleString(); descriptor: ()Ljava/lang/String; public java.lang.String toGMTString(); descriptor: ()Ljava/lang/String; public int getTimezoneOffset(); descriptor: ()I private final sun.util.calendar.BaseCalendar$Date getCalendarDate(); descriptor: ()Lsun/util/calendar/BaseCalendar$Date; private final sun.util.calendar.BaseCalendar$Date normalize(); descriptor: ()Lsun/util/calendar/BaseCalendar$Date; private final sun.util.calendar.BaseCalendar$Date normalize(sun.util.calendar.BaseCalendar$Date); descriptor: (Lsun/util/calendar/BaseCalendar$Date;)Lsun/util/calendar/BaseCalendar$Date; private static final sun.util.calendar.BaseCalendar getCalendarSystem(int); descriptor: (I)Lsun/util/calendar/BaseCalendar; private static final sun.util.calendar.BaseCalendar getCalendarSystem(long); descriptor: (J)Lsun/util/calendar/BaseCalendar; private static final sun.util.calendar.BaseCalendar getCalendarSystem(sun.util.calendar.BaseCalendar$Date); descriptor: (Lsun/util/calendar/BaseCalendar$Date;)Lsun/util/calendar/BaseCalendar; private static final synchronized sun.util.calendar.BaseCalendar getJulianCalendar(); descriptor: ()Lsun/util/calendar/BaseCalendar; private void writeObject(java.io.ObjectOutputStream) throws java.io.IOException; descriptor: (Ljava/io/ObjectOutputStream;)V private void readObject(java.io.ObjectInputStream) throws java.io.IOException, java.lang.ClassNotFoundException; descriptor: (Ljava/io/ObjectInputStream;)V public static java.util.Date from(java.time.Instant); descriptor: (Ljava/time/Instant;)Ljava/util/Date; public java.time.Instant toInstant(); descriptor: ()Ljava/time/Instant; public int compareTo(java.lang.Object); descriptor: (Ljava/lang/Object;)I static {}; descriptor: ()V } C:\Users\renzhenming> 1.在Java的一个类中,如下,定义各种类型的属性和方法 import java.util.Random; import java.util.UUID; public class JniUtils { public String key = "renzhenming"; private Human human = new Man(); public static int count = 9; public native static String getStringFromC(); public native String getString2FromC(int i); //访问属性,返回修改之后的属性内容 public native String accessField(); public native void accessStaticField(); public native void accessMethod(); public native void accessStaticMethod(); public native void accessNonVirtualMethod(); public native String toChineseString(String value); public native void accessConstructor(); public native void setArray(int [] arr); public native int[] getArray(); public native void cached(); public native static void initIds(); public static void main(String[] args) { String text = getStringFromC(); System.out.println(text); JniUtils t = new JniUtils(); text = t.getString2FromC(6); System.out.println(text); System.out.println("key修改前:"+t.key); t.accessField(); System.out.println("key修改后:"+t.key); System.out.println("count修改前:"+count); t.accessStaticField(); System.out.println("count修改后:"+count); t.accessMethod(); t.accessStaticMethod(); System.out.println("访问构造方法"); new JniUtils().accessConstructor(); System.out.println("访问被子类重写后的父类方法"); new JniUtils().accessNonVirtualMethod(); System.out.println(new JniUtils().toChineseString("想乱码的日子里")); int arr [] = {12,3,43,55,44,1,566}; new JniUtils().setArray(arr); for(int i = 0 ; i < arr.length;i++ ) { System.out.println(arr[i]); } System.out.println("-------------------------------"); int [] jarr = new JniUtils().getArray(); for(int i = 0 ; i < jarr.length;i++ ) { System.out.println(jarr[i]); } System.out.println("-------------------------------"); new JniUtils().createGlobalRef(); System.out.println(new JniUtils().getGlobalRef()); new JniUtils().deleteGlobalRef(); //释放了再获取就会空指针 //System.out.println(new JniUtils().getGlobalRef()); try { new JniUtils().exception(); } catch (Exception e) { System.out.println("发生异常:"+e.getMessage()); } //不断调用cached方法 for (int i = 0; i < 100; i++) { t.cached(); } } //产生指定范围的随机数 public int genRandomInt(int max){ System.out.println("genRandomInt 执行了..."); return new Random().nextInt(max); } //产生UUID字符串 public static String getUUID(){ return UUID.randomUUID().toString(); } //加载动态库 static{ System.loadLibrary("JniTest");//这是生成的dll动态库的名字 initIds(); } } //类Human和类Man代码如下(测试jni调用父类方法而设置): public class Human { public void sayHi() { System.out.println("人打招呼"); } } public class Man extends Human{ public void sayHi() { System.out.println("男。。。。。人打招呼"); } } 2.创建native方法,使用javah生成头文件 /* DO NOT EDIT THIS FILE - it is machine generated */ #include "jni.h" /* Header for class com_dongnaoedu_jni_JniTest */ #ifndef _Included_com_renzhenming_bsdiff_JniUtils #define _Included_com_renzhenming_bsdiff_JniUtils #ifdef __cplusplus extern "C" { #endif /* * Class: _com_renzhenming_bsdiff_JniUtils * Method: getStringFromC * Signature: ()V */ JNIEXPORT jstring JNICALL Java_com_renzhenming_bsdiff_JniUtils_getStringFromC (JNIEnv *, jclass); JNIEXPORT jstring JNICALL Java_com_renzhenming_bsdiff_JniUtils_getString2FromC (JNIEnv *, jobject, jint); JNIEXPORT jstring JNICALL Java_com_renzhenming_bsdiff_JniUtils_accessField (JNIEnv *, jobject); JNIEXPORT void JNICALL Java_com_renzhenming_bsdiff_JniUtils_accessStaticField (JNIEnv *, jobject); JNIEXPORT void JNICALL Java_com_renzhenming_bsdiff_JniUtils_accessMethod (JNIEnv *, jobject); JNIEXPORT void JNICALL Java_com_renzhenming_bsdiff_JniUtils_accessStaticMethod (JNIEnv *, jobject); JNIEXPORT void JNICALL Java_com_renzhenming_bsdiff_JniUtils_accessConstructor (JNIEnv *, jobject); JNIEXPORT void JNICALL Java_com_renzhenming_bsdiff_JniUtils_accessNonVirtualMethod (JNIEnv *, jobject); JNIEXPORT jstring JNICALL Java_com_renzhenming_bsdiff_JniUtils_toChineseString (JNIEnv *, jobject, jstring); JNIEXPORT void JNICALL Java_com_renzhenming_bsdiff_JniUtils_setArray (JNIEnv *,jobject,jintArray); JNIEXPORT jintArray JNICALL Java_com_renzhenming_bsdiff_JniUtils_getArray (JNIEnv *, jobject); JNIEXPORT void JNICALL Java_com_renzhenming_bsdiff_JniUtils_localRef (JNIEnv *, jobject); JNIEXPORT void JNICALL Java_com_renzhenming_bsdiff_JniUtils_createGlobalRef (JNIEnv *,jobject); JNIEXPORT jstring JNICALL Java_com_renzhenming_bsdiff_JniUtils_getGlobalRef (JNIEnv *, jobject); JNIEXPORT void JNICALL Java_com_renzhenming_bsdiff_JniUtils_deleteGlobalRef (JNIEnv *, jobject); JNIEXPORT void JNICALL Java_com_renzhenming_bsdiff_JniUtils_exception (JNIEnv *, jobject); #ifdef __cplusplus } #endif #endif 3.将头文件引入as中(jni.h和jni_md.h引入同上次笔记),编写c代码,如下 #define _CRT_SECURE_NO_WARNINGS #include "com_renzhenming_bsdiff_JniUtils.h" #include <string.h> //功能:获取到指定类中一字符串类型成员变量,修改返回得到新的字符串 JNIEXPORT jstring JNICALL Java_com_renzhenming_bsdiff_JniUtils_changeKey (JNIEnv *env, jobject jobj) { //我们编写的native方法是非静态方法,所以这里是jobject,而我们需要jclass来获取fieldid,所以这样转换 jclass clazz = (*env)->GetObjectClass(env, jobj); //参数分别为class对象,属性名,属性签名(签名得到的方法查看文档),获取到我们需要修改的属性的id值 jfieldID fieldId = (*env)->GetFieldID(env, clazz, "key", "Ljava/lang/String;"); //从这个对象jobj中获取这个id fieldid的jstring 对象 jstring jstr = (*env)->GetObjectField(env, jobj, fieldId); //将jni类型jstring 转换为c对象char ,从而我们可以调用c方法修改这个对象的值 char *c_str = (*env)->GetStringUTFChars(env, jstr, JNI_FALSE); //将这个对象的值和text这个字符串连接得到我们需要的新值 char text[30] = "handsome "; strcat(text, c_str); //再次将这个新值对应的c对象char转换为jni类型jstring, jstring new_jstr = (*env)->NewStringUTF(env, text); //将这个jstring类型的新对象设置给这个jobj这个对象中id值为fieldId的这个对象,至此对象值已经被我们修改 (*env)->SetObjectField(env, jobj, fieldId, new_jstr); //删除 (*env)->DeleteLocalRef(env,new_jstr); //返回这个新的字符串,这里没有用到 return new_jstr; } #define _CRT_SECURE_NO_WARNINGS #include "com_renzhenming_bsdiff_JniUtils.h" #include <string.h> //函数实现 JNIEXPORT jstring JNICALL Java_com_renzhenming_bsdiff_JniUtils_getStringFromC (JNIEnv *env, jclass jcls){ return (*env)->NewStringUTF(env,"C String"); } JNIEXPORT jstring JNICALL Java_com_renzhenming_bsdiff_JniUtils_getString2FromC (JNIEnv *env, jobject jobj, jint num){ return (*env)->NewStringUTF(env,"C String2"); } //每个native函数,都至少有两个参数(JNIEnv*,jclass或者jobject) //1)当native方法为静态方法时: //jclass 代表native方法所属类的class对象(JniTest.class) //2)当native方法为非静态方法时: //jobject 代表native方法所属的对象 //基本数据 //Java基本数据类型与JNI数据类型的映射关系 //Java类型->JNI类型->C类型 /* boolean jboolean byte jbyte; char jchar; short jshort; int jint; long jlong; float jfloat; double jdouble; void void */ //引用类型(对象) //String jstring //object jobject //数组,基本数据类型的数组 //byte[] jByteArray //对象数组 //object[](String[]) jobjectArray //C/C++访问Java的成员 //1.访问属性 //修改属性key JNIEXPORT jstring JNICALL Java_com_renzhenming_bsdiff_JniUtils_accessField (JNIEnv *env, jobject jobj){ //我们编写的native方法是非静态方法,所以这里是jobject,而我们需要jclass来获取fieldid,所以这样转换 jclass clazz = (*env)->GetObjectClass(env, jobj); //参数分别为class对象,属性名,属性签名(签名得到的方法查看文档),获取到我们需要修改的属性的id值 jfieldID fieldId = (*env)->GetFieldID(env, clazz, "key", "Ljava/lang/String;"); //从这个对象jobj中获取这个id fieldid的jstring 对象 jstring jstr = (*env)->GetObjectField(env, jobj, fieldId); //将jni类型jstring 转换为c对象char ,从而我们可以调用c方法修改这个对象的值 char *c_str = (*env)->GetStringUTFChars(env, jstr, JNI_FALSE); //将这个对象的值和text这个字符串连接得到我们需要的新值 char text[30] = "handsome "; strcat(text, c_str); //再次将这个新值对应的c对象char转换为jni类型jstring, jstring new_jstr = (*env)->NewStringUTF(env, text); //将这个jstring类型的新对象设置给这个jobj这个对象中id值为fieldId的这个对象,至此对象值已经被我们修改 (*env)->SetObjectField(env, jobj, fieldId, new_jstr); (*env)->DeleteLocalRef(env,new_jstr); //返回这个新的字符串,这里没有用到 return new_jstr; } //访问静态属性 JNIEXPORT void JNICALL Java_com_renzhenming_bsdiff_JniUtils_accessStaticField (JNIEnv *env, jobject jobj){ //jclass jclass cls = (*env)->GetObjectClass(env, jobj); //jfieldID jfieldID fid = (*env)->GetStaticFieldID(env, cls, "count", "I"); //GetStatic<Type>Field jint count = (*env)->GetStaticIntField(env, cls, fid); count++; //修改 //SetStatic<Type>Field (*env)->SetStaticIntField(env,cls,fid,count); } //2.访问java方法 JNIEXPORT void JNICALL Java_com_renzhenming_bsdiff_JniUtils_accessMethod (JNIEnv *env, jobject jobj){ //jclass jclass cls = (*env)->GetObjectClass(env, jobj); //jmethodID jmethodID mid = (*env)->GetMethodID(env, cls, "genRandomInt", "(I)I"); //调用 //Call<Type>Method jint random = (*env)->CallIntMethod(env, jobj, mid, 200); printf("random num:%ld",random); //..... } //静态方法 JNIEXPORT void JNICALL Java_com_renzhenming_bsdiff_JniUtils_accessStaticMethod (JNIEnv *env, jobject jobj){ //jclass jclass cls = (*env)->GetObjectClass(env, jobj); //jmethodID jmethodID mid = (*env)->GetStaticMethodID(env, cls, "getUUID", "()Ljava/lang/String;"); //调用 //CallStatic<Type>Method jstring uuid = (*env)->CallStaticObjectMethod(env, cls, mid); //随机文件名称 uuid.txt //jstring -> char* //isCopy JNI_FALSE,代表java和c操作的是同一个字符串 char *uuid_str = (*env)->GetStringUTFChars(env, uuid, JNI_FALSE); //拼接 char filename[100]; sprintf(filename, "D://%s.txt",uuid_str); //w 打开只写文件,若文件存在则文件长度清为0,即该文件内容会消失。若文件不存在则建立该文件。 FILE *fp = fopen(filename,"w"); fputs("i love jason", fp); fclose(fp); } //访问构造方法(Date 生成一个时间戳) JNIEXPORT void JNICALL Java_com_renzhenming_bsdiff_JniUtils_accessConstructor (JNIEnv *env, jobject jobj) { //根据包名得到类,类似反射 jclass cls = (*env)->FindClass(env, "java/util/Date"); //获取类中要获取的方法id(获取构造方法,方法名传"<init>") jmethodID methodid = (*env)->GetMethodID(env, cls, "<init>", "()V"); //实例化一个对象,类似反射 jobject date_obj = (*env)->NewObject(env, cls, methodid); //通过这个对象调用getTime方法,需要获取到这个方法的id jmethodID g_methodid = (*env)->GetMethodID(env, cls, "getTime", "()J"); //执行这个方法,返回值是long类型,所以CallLong jlong time = (*env)->CallLongMethod(env, date_obj, g_methodid); //占位符用的lld,是long long类型的,如果直接用ld占位符打印,打出的是负数 printf("\ntime:%lld\n", time); (*env)->DeleteLocalRef(env,date_obj); } //访问父类被子类重写的方法 JNIEXPORT void JNICALL Java_com_renzhenming_bsdiff_JniUtils_accessNonVirtualMethod (JNIEnv *env, jobject jobj) { //在java中,父类指向子类对象,调用被子类重写的方法,执行的是子类的方法,在jni中 //我们可以调用到父类的方法 jclass cls = (*env)->GetObjectClass(env, jobj); //获取类中human属性(先获取到id) 对象的签名 jfieldID fid = (*env)->GetFieldID(env, cls, "human", "Lcom/renzhenming/bsdiff/Human;"); jobject human_obj = (*env)->GetObjectField(env, jobj, fid); //获取父类class jclass human_class = (*env)->FindClass(env, "com/renzhenming/bsdiff/Human"); //获取父类中需要调用的方法的methodid jmethodID s_mid = (*env)->GetMethodID(env,human_class,"sayHi","()V"); //执行指定方法 //子类方法 (*env)->CallObjectMethod(env, human_obj, s_mid); //父类方法(c++中要重写父类方法,用的是virtual关键字)(调用父类方法传入的class不能通过 //GetObjectClass从human_obj中获取,因为这样获取到的是子类的class) (*env)->CallNonvirtualObjectMethod(env, human_obj, human_class, s_mid); } //解决jni中文乱码的问题 JNIEXPORT jstring JNICALL Java_com_renzhenming_bsdiff_JniUtils_toChineseString_ (JNIEnv *env, jobject jobj, jstring jstr) { //输出 //char *c_str = (*env)->GetStringUTFChars(env, in, JNI_FALSE); //printf("%s\n",c_str); //c -> jstring char *c_str = "马蓉与宋江"; //char c_str[] = "马蓉与宋喆"; //jstring jstr = (*env)->NewStringUTF(env, c_str); //执行String(byte bytes[], String charsetName)构造方法需要的条件 //1.jmethodID //2.byte数组 //3.字符编码jstring jclass str_cls = (*env)->FindClass(env, "java/lang/String"); jmethodID constructor_mid = (*env)->GetMethodID(env, str_cls, "<init>", "([BLjava/lang/String;)V"); //jbyte -> char //jbyteArray -> char[] jbyteArray bytes = (*env)->NewByteArray(env, strlen(c_str)); //byte数组赋值 //0->strlen(c_str),从头到尾 //对等于,从c_str这个字符数组,复制到bytes这个字符数组 (*env)->SetByteArrayRegion(env, bytes, 0, strlen(c_str), c_str); //字符编码jstring jstring charsetName = (*env)->NewStringUTF(env, "GB2312"); //调用构造函数,返回编码之后的jstring return (*env)->NewObject(env, str_cls, constructor_mid, bytes, charsetName); } //-----------------------操作数组涉及到数组的同步问题(ReleaseIntArrayElements)-----------------------------// //操作传入的数组 JNIEXPORT void JNICALL Java_com_renzhenming_bsdiff_JniUtils_setArray (JNIEnv *env, jobject jobj, jintArray array) { //jintArray ->jint指针->c int数组 jint *elems = (*env)->GetIntArrayElements(env, array, JNI_FALSE); //数组的长度 int len = (*env)->GetArrayLength(env, array); //排序(传入的compare类似Java中的比较器) qsort(elems, len, sizeof(jint), compare); //将排序结果同步到Java中的数组 //最后一个参数 mode //0 表示Java数组进行更新,并且释放c/c++数组 //JNI_ABORT 表示Java数组不更新,释放c/c++数组 //JNI_COMMIT 表示Java数组进行更新,但不释放c/c++数组 (*env)->ReleaseIntArrayElements(env, array, elems, 0); } //返回一个数组 JNIEXPORT jintArray JNICALL Java_com_renzhenming_bsdiff_JniUtils_getArray (JNIEnv *env, jobject jobj) { //创建一个指定大小的数组 jintArray jint_arr = (*env)->NewIntArray(env, 10); //获取到数组指针 jint *elems = (*env)->GetIntArrayElements(env, jint_arr, NULL); int i = 0; for ( ; i< 10; i++) { elems[i] = i; } //同步 (*env)->ReleaseIntArrayElements(env, jint_arr, elems, 0); return jint_arr; } //局部引用 JNIEXPORT void JNICALL Java_com_renzhenming_bsdiff_JniUtils_localRef (JNIEnv *env, jobject jobj) { int i = 0; for (; i < 5; i++) { //创建对象,以Date为例 jclass cls = (*env)->FindClass(env, "java/util/Date"); jmethodID constructor_id = (*env)->GetMethodID(env, cls, "init", "()V"); jobject obj = (*env)->NewObject(env, cls, constructor_id); //.... //不在使用这个对象了需要回收 (*env)->DeleteLocalRef(env, obj); //.... } } //创建全局引用(共享,可以跨多个线程) jstring global_str; JNIEXPORT void JNICALL Java_com_renzhenming_bsdiff_JniUtils_createGlobalRef (JNIEnv *env, jobject jobj) { jstring jstr = (*env)->NewStringUTF(env,"jni is a bitch"); global_str = (*env)->NewGlobalRef(env, jstr); } //获取全局引用 JNIEXPORT jstring JNICALL Java_com_renzhenming_bsdiff_JniUtils_getGlobalRef (JNIEnv *env, jobject jobj) { return global_str; } //删除全局引用 JNIEXPORT void JNICALL Java_com_renzhenming_bsdiff_JniUtils_deleteGlobalRef (JNIEnv *env, jobject jobj) { (*env)->DeleteGlobalRef(env, global_str); } //Java捕获c异常(如果不做抛异常处理,直接再Java层try是抓不到异常信息的) JNIEXPORT void JNICALL Java_com_renzhenming_bsdiff_JniUtils_exception (JNIEnv *env, jobject jobj) { jclass cls = (*env)->GetObjectClass(env, jobj); jfieldID fid = (*env)->GetFieldID(env, cls, "value2", "Ljava/lang/String;"); //检测是否发生Java异常 jthrowable exception = (*env)->ExceptionOccurred(env); if (exception != NULL) { //让Java代码可以继续运行 //清空异常信息 (*env)->ExceptionClear(env); //补救措施 fid = (*env)->GetFieldID(env, cls, "value", "Ljava/lang/String;"); } //获取属性值 jstring jstr = (*env)->GetObjectField(env, jobj, fid); char *str = (*env)->GetStringUTFChars(env, jstr, NULL); //对比属性是否合法 if (stricmp(str, "renzhenming") != 0) { //抛出异常,给Java处理 jclass newExcCls = (*env)->FindClass(env, "java/lang/IllegalArgumentException"); (*env)->ThrowNew(env, newExcCls, "key's value is invalid!"); } } //静态缓存 //static jfieldID key_id JNIEXPORT void JNICALL Java_com_renzhenming_bsdiff_JniUtils_cached(JNIEnv *env, jobject jobj){ jclass cls = (*env)->GetObjectClass(env, jobj); //»ñÈ¡jfieldIDÖ»»ñȡһ´Î //¾Ö²¿¾²Ì¬±äÁ¿ static jfieldID key_id = NULL; if (key_id == NULL){ key_id = (*env)->GetFieldID(env, cls, "key", "Ljava/lang/String;"); printf("--------GetFieldID-------\n"); } } //加载动态库的时候就初始化全局变量,再loadLibrary后调用 jfieldID key_fid; jmethodID random_mid; JNIEXPORT void JNICALL Java_com_renzhenming_bsdiff_JniUtils_initIds(JNIEnv *env, jclass jcls){ key_fid = (*env)->GetFieldID(env, jcls, "key", "Ljava/lang/String;"); random_mid = (*env)->GetMethodID(env, jcls, "genRandomInt", "(I)I"); } 4.生成dll动态库,放到eclipse中调用 public static void main(String[] args) { String text = getStringFromC(); System.out.println(text); JniTest t = new JniTest(); text = t.getString2FromC(6); System.out.println(text); System.out.println("key修改前:"+t.key); t.accessField(); System.out.println("key修改后:"+t.key); System.out.println("count修改前:"+count); t.accessStaticField(); System.out.println("count修改后:"+count); t.accessMethod(); t.accessStaticMethod(); System.out.println("访问构造方法"); new JniUtils().accessConstructor(); System.out.println("访问被子类重写后的父类方法"); new JniUtils().accessNonVirtualMethod(); System.out.println(new JniUtils().toChineseString("想乱码的日子里")); int arr [] = {12,3,43,55,44,1,566}; new JniUtils().setArray(arr); for(int i = 0 ; i < arr.length;i++ ) { System.out.println(arr[i]); } System.out.println("-------------------------------"); int [] jarr = new JniUtils().getArray(); for(int i = 0 ; i < jarr.length;i++ ) { System.out.println(jarr[i]); } System.out.println("-------------------------------"); new JniUtils().createGlobalRef(); System.out.println(new JniUtils().getGlobalRef()); new JniUtils().deleteGlobalRef(); //释放了再获取就会空指针 //System.out.println(new JniUtils().getGlobalRef()); try { new JniUtils().exception(); } catch (Exception e) { System.out.println("发生异常:"+e.getMessage()); } }

优秀的个人博客,低调大师

01.Jni开发流程_java调用C/C++

(创建于2017/11/18) JNI(Java Native Interface) Java调用C/C++,C/C++调用Java的一套API 1.编写native方法 public class JniUtils { public static native String getStringFromC(); public native String getStringFromC2(); } 2.javah命令,生成.h头文件 cd 进入到src目录下,使用命令生成头文件 javah 包名+类型(如 com.renzhenming.utils.JniUtils) 3.复制.h头文件到CPP工程中 右键->添加现有项->将头文件添加到vs中的头文件目录中,不要直接复制,直接复制无效 4.复制jni.h和jni_md.h文件到CPP工程中 发现在我们生成的头文件中有对jni.h 的导入,jni.h中又有对jni_md.h的导入,所以我们直接去jdk目录下搜索道这两个头文件,引入到工程中,同样是添加现有项 注意include的时候,<>与“”的灵活使用,假设生成的头文件是这样的(有时候Javah命令生成的头文件中没有方法名,只有一些预编译的东西,不知何故) /* DO NOT EDIT THIS FILE - it is machine generated */ #include "jni.h" /* Header for class com_renzhenming_bsdiff_JniUtils */ #ifndef _Included_com_renzhenming_bsdiff_JniUtils #define _Included_com_renzhenming_bsdiff_JniUtils #ifdef __cplusplus extern "C" { #endif /* * Class: com_renzhenming_bsdiff_JniUtils * Method: getStringFromC * Signature: ()Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_com_renzhenming_bsdiff_JniUtils_getStringFromC (JNIEnv *, jclass); /* * Class: com_renzhenming_bsdiff_JniUtils * Method: getStringFromC2 * Signature: ()Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_com_renzhenming_bsdiff_JniUtils_getStringFromC2 (JNIEnv *, jobject); #ifdef __cplusplus } #endif #endif 5.实现.h头文件中声明的函数 假设如上边一样,我们生成了头文件,那么我们需要在自己的c文件中定义实现这两个方法 #include "com_renzhenming_bsdiff_JniUtils.h" //引入头文件 JNIEXPORT jstring JNICALL Java_com_renzhenming_bsdiff_JniUtils_getStringFromC (JNIEnv *env, jclass jcls) { return (*env)->NewStringUTF(env, "aaaaaaa"); //得到字符串 } JNIEXPORT jstring JNICALL Java_com_renzhenming_bsdiff_JniUtils_getStringFromC2 (JNIEnv *env, jobject jobj) { return (*env)->NewStringUTF(env, "bbbbbb");//得到字符串 } 6.visual studio生成dll文件 37761343.png 如上点击debug出现下拉框,选择配置管理器,将我们的活动解决方案设置为x64 37833718.png 右键项目名->属性,设置常规下的项目默认值下的配置类型选择动态库(.dll),然后 37905203.png 点击生成,选择生成解决方案,这时候我们的dll动态库就生成在指定目录中了 37963765.png 7.vs生成dll动态库的时候容易出现的问题和解决方法 1.使用了过时的函数 严重性 代码 说明 项目 文件 行 禁止显示状态 错误 C4996 'open': The POSIX name for this item is deprecated. Instead, use the ISO C and C++ conformant name: _open. See online help for details. ndk_update c:\users\renzhenming\documents\visual studio 2015\projects\ndk_update\ndk_update\bsdiff.cpp 263 解决办法:给所在的类添加宏定义 define _CRT_NONSTDC_NO_DEPRECATE 或者给整个项目添加右键项目名->属性->配置属性->c/c++->命令行,在其他选项中添加 -D _CRT_NONSTDC_NO_DEPRECATE,确定即可,这样会给整个项目设置这个配置,不再需要在每个类中分别添加了 2.使用了不安全的函数 严重性 代码 说明 项目 文件 行 禁止显示状态 错误 C4996 'open': This function or variable may be unsafe. Consider using _sopen_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details. ndk_update c:\users\renzhenming\documents\visual studio 2015\projects\ndk_update\ndk_update\bsdiff.cpp 263 解决办法:同上的方式添加宏定义,_CRT_SECURE_NO_WARNINGS 3.安全性检查相关的问题 bsdiff是外国程序员写的,可能使用的工具不是vs,而vs对代码安全性检查比较严格,所以导致这个问题 在linux系统下不会报这个错误 严重性 代码 说明 项目 文件 行 禁止显示状态 错误 C4703 使用了可能未初始化的本地指针变量“old” ndk_update c:\users\renzhenming\documents\visual studio 2015\projects\ndk_update\ndk_update\bsdiff.cpp 266 错误 C4703 使用了可能未初始化的本地指针变量“V” ndk_update c:\users\renzhenming\documents\visual studio 2015\projects\ndk_update\ndk_update\bsdiff.cpp 273 错误 C4703 使用了可能未初始化的本地指针变量“_new” ndk_update c:\users\renzhenming\documents\visual studio 2015\projects\ndk_update\ndk_update\bsdiff.cpp 295 解决办法:右键项目名->属性->配置属性->c/c++->常规->SDL检查选择否 4.重复引用的问题 这个错误的原因是因为项目中既添加了bsdiff.cpp也添加了bspatch.cpp文件,导致出现定义的重复问题 也就是二者不可同时存在,移除一个 严重性 代码 说明 项目 文件 行 禁止显示状态 错误 LNK2005 "void __cdecl err(int,char const *)" (?err@@YAXHPEBD@Z) 已经在 bsdiff.obj 中定义 ndk_update c:\Users\renzhenming\Documents\Visual Studio 2015\Projects\ndk_update\ndk_update\bspatch.obj 1 错误 LNK2005 "void __cdecl errx(int,char const *)" (?errx@@YAXHPEBD@Z) 已经在 bsdiff.obj 中定义 ndk_update c:\Users\renzhenming\Documents\Visual Studio 2015\Projects\ndk_update\ndk_update\bspatch.obj 1 错误 LNK1169 找到一个或多个多重定义的符号 ndk_update c:\Users\renzhenming\Documents\Visual Studio 2015\Projects\ndk_update\x64\Debug\ndk_update.exe 1 解决办法:针对这个项目的编译,不要让两者同时存在

资源下载

更多资源
优质分享App

优质分享App

近一个月的开发和优化,本站点的第一个app全新上线。该app采用极致压缩,本体才4.36MB。系统里面做了大量数据访问、缓存优化。方便用户在手机上查看文章。后续会推出HarmonyOS的适配版本。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

用户登录
用户注册