机械厂网站建设方案,活动网页怎么做,怎么买网站,网页版传奇世界羽翼升级JNI的数据类型和类型签名
数据类型
JNI的数据类型包含两种#xff1a;基本类型和引用类型。
基本类型主要有jboolean、jchar、jint等#xff0c;它们和Java中的数据类型的对应关系如下表所示。 JNI中的引用类型主要有类、对象和数组#xff0c;它们和Java中的引用类型的对…JNI的数据类型和类型签名
数据类型
JNI的数据类型包含两种基本类型和引用类型。
基本类型主要有jboolean、jchar、jint等它们和Java中的数据类型的对应关系如下表所示。 JNI中的引用类型主要有类、对象和数组它们和Java中的引用类型的对应关系如下表所示。 当然JNI 中还有个 Java 中没有的 jsize定义如下
typedef jint jsize;其实jsize整型是用来描述基本指标和大小没有什么神秘的。
类型签名
JNI的类型签名标识了一个特定的Java类型这个类型既可以是类和方法也可以是数据类型。
类的签名比较简单它采用 “L包名类名; ” 的形式只需要将其中的替换为/即可。比如java.lang.String它的签名为Ljava/lang/String;注意末尾的也是签名的一部分。
基本数据类型的签名采用一系列大写字母来表示如下表所示。 从上表可以看出基本数据类型的签名是有规律的一般为首字母的大写但是boolean除外因为B已经被byte占用了而long的签名之所以不是L那是因为L表示的是类的签名。
对象和数组的签名稍微复杂一些。对于对象来说它的签名就是对象所属的类的签名比如String对象它的签名为Ljava/lang/String;。对于数组来说它的签名为[类型签名比如int数组其类型为int而int的签名为I所以int数组的签名就是[I同理就可以得出如下的签名对应关系
char[] [C
float[] [F
double[] [D
long[] [J
String[] [Ljava/lang/String;
Object[] [Ljava/lang/Object;对于多维数组来说它的签名为n个[类型签名其中n表示数组的维度比如int[][]的签名为[[I其他情况可以依此类推。
方法的签名为参数类型签名返回值类型签名这有点不好理解。举个例子如下方法boolean fun1(int a, double b, int[] c)根据签名的规则可以知道它的参数类型的签名连在一起是ID[I返回值类型的签名为Z所以整个方法的签名就是(ID[I)Z。再举个例子下面的方法boolean fun1(int a, String b, int[] c)它的签名是(ILjava/lang/String; [I)Z。为了能够更好地理解方法的签名格式下面再给出两个示例
int fun1() 签名为 ()I
void fun1(int i) 签名为 (I)V一个Java类的方法的Signature可以通过javap命令获取javap -s -p Java类名
本地方法中访问java程序中的内容 1. 访问 String 对象
从java程序中传过去的String对象在本地方法中对应的是jstring类型jstring类型和c中的char*不同所以如果你直接当做 char*使用的话就会出错。因此在使用之前需要将jstring转换成为c/c中的char*这里使用JNIEnv的方法转换。下面是一个例子
JNIEXPORT jstring JNICALL Java_Prompt_getLine(JNIEnv *env, jobject obj, jstring prompt)
{char buf[128];const char *str (*env)-GetStringUTFChars(env, prompt, 0);printf(%s, str);(*env)-ReleaseStringUTFChars(env, prompt, str);
}这里使用GetStringUTFChars方法将传进来的promptjstring类型转换成为UTF-8的格式就能够在本地方法中使用了。
注意在使用完你所转换之后的对象之后需要显示调用ReleaseStringUTFChars方法让JVM释放转换成UTF-8的string的对象的空间如果不显示的调用的话JVM中会一直保存该对象不会被垃圾回收器回收因此就会导致内存溢出。
下面是访问String的一些方法
GetStringUTFChars将jstring转换成为UTF-8格式的char*GetStringChars将jstring转换成为Unicode格式的char*ReleaseStringUTFChars释放指向UTF-8格式的char*的指针ReleaseStringChars释放指向Unicode格式的char*的指针NewStringUTF创建一个UTF-8格式的String对象NewString创建一个Unicode格式的String对象GetStringUTFLength获取UTF-8格式的char*的长度GetStringLength获取Unicode格式的char*的长度
2. 访问 Array 对象
和String对象一样在本地方法中不能直接访问jarray对象而是使用JNIEnv指针指向的一些方法来使用。 访问Java原始类型数组
1获取数组的长度
JNIEXPORT jint JNICALL Java_IntArray_sumArray(JNIEnv *env, jobject obj, jintArray arr)
{int i, sum 0;jsize len (*env)-GetArrayLength(env, arr);
}这里获取数组的长度和普通的c语言中的获取数组长度不一样这里使用JNIEnv的一个函数GetArrayLength。
2获取一个指向数组元素的指针
jint *body (*env)-GetIntArrayElements(env, arr, 0);使用GetIntArrayElements方法获取指向arr数组元素的指针注意该函数的参数第一个是JNIEnv第二个是数组第三个是数组里面开始的元素。
3使用指针取出 Array 中的元素
for (i0; ilen; i) {sum body[i];
}这里使用就和普通的c中的数组使用没有什么不同了
4释放数组元素的引用
(*env)-ReleaseIntArrayElements(env, arr, body, 0);和操作String中的释放String的引用是一样的提醒JVM回收arr数组元素的引用。
这里举的例子是使用int数组的同样还有boolean、float等对应的数组。
获取数组和释放数组元素指针的对应关系
数组类型获取函数释放函数booleanGetBooleanArrayElementsReleaseBooleanArrayElementsbyteGetByteArrayElementsReleaseByteArrayElementscharGetCharArrayElementsReleaseCharArrayElementsshortGetShortArrayElementsReleaseShortArrayElementsintGetIntArrayElementsReleaseIntArrayElementslongGetLongArrayElementsReleaseLongArrayElementsfloatGetFloatArrayElementsReleaseFloatArrayElementsdoubleGetDoubleArrayElementsReleaseDoubleArrayElements GetObjectArrayElement returns the object element at a given index.SetObjectArrayElement updates the object element at a given index.
3. 访问Java对象的方法
JNI调用Java方法的流程是先通过类名找到类然后再根据方法名找到方法的id最后就可以调用这个方法了。如果是调用Java中的非静态方法那么需要构造出类的对象后才能调用它。 在本地方法中调用Java对象的方法的步骤 ① 获取你需要访问的Java对象的Class类
jclass cls (*env)-GetObjectClass(env, obj);使用GetObjectClass方法获取obj对应的jclass。 ② 获取MethodID
jmethodID mid (*env)-GetMethodID(env, cls, callback, (I)V);使用GetMethdoID方法获取你要使用的方法的MethdoID。其参数的意义
envJNIEnvcls第一步获取的jclasscallback要调用的方法名(I)V方法的Signature
③ 调用方法
(*env)-CallVoidMethod(env, obj, mid, depth);使用CallVoidMethod方法调用方法。参数的意义
envJNIEnv指针obj调用该native方法的jobject对象mid方法的methodID即第二步获得的MethodIDdepth方法需要的参数对应方法的需求添加相应的参数可以是可变参数
注这里使用的是CallVoidMethod方法调用因为没有返回值如果有返回值的话要使用对应的方法。
除了CallVoidMethod外针对每种基本类型的方法都有不同的重载如下
jobject (*CallObjectMethod)(JNIEnv*, jobject, jmethodID, ...);
jobject (*CallObjectMethodV)(JNIEnv*, jobject, jmethodID, va_list);
jobject (*CallObjectMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);
jboolean (*CallBooleanMethod)(JNIEnv*, jobject, jmethodID, ...);
jboolean (*CallBooleanMethodV)(JNIEnv*, jobject, jmethodID, va_list);
jboolean (*CallBooleanMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);
jbyte (*CallByteMethod)(JNIEnv*, jobject, jmethodID, ...);
jbyte (*CallByteMethodV)(JNIEnv*, jobject, jmethodID, va_list);
jbyte (*CallByteMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);
jchar (*CallCharMethod)(JNIEnv*, jobject, jmethodID, ...);
jchar (*CallCharMethodV)(JNIEnv*, jobject, jmethodID, va_list);
jchar (*CallCharMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);
jshort (*CallShortMethod)(JNIEnv*, jobject, jmethodID, ...);
jshort (*CallShortMethodV)(JNIEnv*, jobject, jmethodID, va_list);
jshort (*CallShortMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);
jint (*CallIntMethod)(JNIEnv*, jobject, jmethodID, ...);
jint (*CallIntMethodV)(JNIEnv*, jobject, jmethodID, va_list);
jint (*CallIntMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);
jlong (*CallLongMethod)(JNIEnv*, jobject, jmethodID, ...);
jlong (*CallLongMethodV)(JNIEnv*, jobject, jmethodID, va_list);
jlong (*CallLongMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);
jfloat (*CallFloatMethod)(JNIEnv*, jobject, jmethodID, ...);
jfloat (*CallFloatMethodV)(JNIEnv*, jobject, jmethodID, va_list);
jfloat (*CallFloatMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);
jdouble (*CallDoubleMethod)(JNIEnv*, jobject, jmethodID, ...);
jdouble (*CallDoubleMethodV)(JNIEnv*, jobject, jmethodID, va_list);
jdouble (*CallDoubleMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);
void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...);
void (*CallVoidMethodV)(JNIEnv*, jobject, jmethodID, va_list);
void (*CallVoidMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); 给调用的函数传参数
通常我们直接在methodID后面将要传的参数添加在后面但是还有其他的方法也可以传参数
CallVoidMethodV可以获取一个数量可变的列表作为参数CallVoidMethodA可以获取一个union。
调用静态方法
就是将第二步和第三步调用的方法改为对应的
GetStaticMethodID获取对应的静态方法的IDCallStaticIntMethod调用静态方法
调用静态方法应该使用对应的CallStaticTypeMethod, 其中的Type随着返回值类型不同而改变参考前面非静态方法列出的类型。
// 首先需要在Java中定义一个静态方法供JNI调用如下所示。
public static void methodCalledByJni(String msgFromJni) {Log.d(TAG, methodCalledByJni, msg: msgFromJni);
}
// 然后在JNI中调用上面定义的静态方法
void callJavaMethod(JNIEnv env, jobject thiz) {jclass clazz env-FindClass(com/ryg/JniTestApp/MainActivity);if (clazz NULL) {printf(find class MainActivity error! );return;}jmethodID id env-GetStaticMethodID(clazz, methodCalledByJni,(Ljava/lang/String; )V);if (id NULL) {printf(find method methodCalledByJni error! );}jstring msg env-NewStringUTF(msg send by callJavaMethod intest.cpp.);env-CallStaticVoidMethod(clazz, id, msg);
}4. 访问Java对象的属性
访问Java对象的属性和访问Java对象的方法基本上一样只需要将函数里面的Method改为Field即可。
GetFieldID获取某个属性的idGetStaticFieldID获取某个静态属性的id
5. 访问Java对象的Class对象
为了能够在C/C中调用Java中的类jni.h的头文件专门定义了jclass类型表示Java中Class类。JNIEnv中有3个函数可以获取jclass jclass FindClass(const char* clsName)通过类的名称来获取jclass。注意是类的全名这时候包名不是用’.“点号而是用”/来区分的。 比如: jclass jcl_stringenv-FindClass(java/lang/String);来获取Java中的String对象的class对象 jclass GetObjectClass(jobject obj)通过对象实例来获取jclass相当于Java中的getClass()函数 jclass getSuperClass(jclass obj)通过jclass可以获取其父类的jclass对象 JNI 和 Java 层之间的数据传输
1 基本数据类型的传输
上层定义一个native的方法需要一个int 参数 返回一个int值JNI 对应上层的方法 打印出上层 传输下来的 int数据并返回 int数据。
上层 收到 native 方法 返回的 值在UI中显示出来
public native int getNumber(int num);jint Java_XX_XX_XXActivity_getNumber(JNIEnv* env,jobject thiz,jint num)
{if(jniEnv NULL) {jniEnv env;}__android_log_print(ANDROID_LOG_INFO, JNIMsg, Java -- C JNI : num %d,num);return num*2;
}注意jint与int的互转都可以直接使用强转如jint i (jint) 10;
2 数组的传输
上层定义一个native的方法需要一个int数组返回一个int数组JNI 对应上层的方法取出上层传递数组中的数据处理和打印出来并存入新数组中最后把该数组返回给 Java层。
上层 收到 native返回的 数组加工成字符串在UI中显示出来
public native int[] getArrayNumber(int[] nums);JNIEnv* jniEnv;
jintArray Java_XX_XX_XXActivity_getArrayNumber(JNIEnv* env,jobject thiz,jintArray nums)
{if(jniEnv NULL) {jniEnv env;}if(nums NULL){return NULL;}jsize len (*jniEnv)-GetArrayLength(jniEnv, nums);if(len 0) {return NULL;}jintArray array (*jniEnv)-NewIntArray(jniEnv, len);if(array NULL) {return NULL;}// 把 Java 传递下来的数组 用 jint* 存起来jint *body (*env)-GetIntArrayElements(env, nums, 0);jint i 0;jint num[len];for (; i len; i) {num[i] body[i] * 2;}if(num NULL){return NULL;}//(*env)-GetIntArrayRegion(env,array,start,len,buffer)// 从start开始复制长度为len 的数据到buffer中//给需要返回的数组赋值(*jniEnv)-SetIntArrayRegion(jniEnv,array, 0, len, num);return array;
}对于其他类型数组使用对应类型的成对方法读取和设置如byte数组可使用 NewByteArray(); 和SetByteArrayRegion();
3 引用数据类型
String 字符串传输
上层定义一个native的方法需要一个String 参数返回一个StringJNI对应上层的方法打印出上层传输下来的String数据并返回处理String数据。
上层 收到 native 方法 返回的 值在UI中显示出来
public native String transferString(String mStrMSG);jstring Java_XX_XX_XXActivity_transferString(JNIEnv* env,jobject thiz,jstring msg)
{if(jniEnv NULL) {jniEnv env;}char data[128];memset(data, 0, sizeof(data));char *c_msg NULL;c_msg (char *)(*jniEnv)-GetStringUTFChars(jniEnv, msg, 0);__android_log_print(ANDROID_LOG_INFO, JNIMsg, C JNI ---- %s,c_msg);return (*jniEnv)-NewStringUTF(jniEnv, This is send by C JNI);
}自定义对象的传输
自定义一个对象Person上层定义一个native方法参数Person返回值PersonJNI接收对象打印出相关信息数据JNI 修改 Person 对象数据并返回到上层。
上层接收到数据后 在UI显示出来
public native Object transferPerson(Person mPerson); public class Person {private String name;private int age;public Person() {name ;age 0;}public String getName() {return name;}public void setName(String name) {this.name name;}public int getAge() {return age;}public void setAge(int age) {this.age age;}Overridepublic String toString() {return Person [name name , age age ];}
}extern JNIEnv* jniEnv;
jclass Person;
jobject mPerson;
jmethodID getName;
jmethodID setName;
jmethodID toString;
int InitPerson();
void ToString();
void GetName();
void SetName();jobject Java_XX_XX_XXActivity_transferPerson(JNIEnv* env,jobject thiz,jobject person)
{if(jniEnv NULL) {jniEnv env;}if (Person NULL || getName NULL || setName NULL || toString NULL) {if (1 ! InitPerson()) {return NULL;}}mPerson person;if(mPerson NULL) {return NULL;}GetName();GetAge();ToString();__android_log_print(ANDROID_LOG_INFO, JNIMsg, Begin Modify mPerson .... );SetName();SetAge();ToString();return mPerson;
}int InitPerson() {if(jniEnv NULL) {return 0;}if(Person NULL) {Person (*jniEnv)-FindClass(jniEnv,com/XX/Person);if(Person NULL){return -1;}}if (getName NULL) {getName (*jniEnv)-GetMethodID(jniEnv, Person, getName,()Ljava/lang/String;);if (getName NULL) {(*jniEnv)-DeleteLocalRef(jniEnv, Person);return -2;}}if (setName NULL) {setName (*jniEnv)-GetMethodID(jniEnv, Person, setName,(Ljava/lang/String;)V);if (setName NULL) {(*jniEnv)-DeleteLocalRef(jniEnv, Person);(*jniEnv)-DeleteLocalRef(jniEnv, getName);return -2;}}if (getAge NULL) {getAge (*jniEnv)-GetMethodID(jniEnv, Person, getAge,()I);if (getAge NULL) {(*jniEnv)-DeleteLocalRef(jniEnv, Person);(*jniEnv)-DeleteLocalRef(jniEnv, getName);(*jniEnv)-DeleteLocalRef(jniEnv, setName);return -2;}}if (setAge NULL) {setAge (*jniEnv)-GetMethodID(jniEnv, Person, setAge,(I)V);if (setAge NULL) {(*jniEnv)-DeleteLocalRef(jniEnv, Person);(*jniEnv)-DeleteLocalRef(jniEnv, getName);(*jniEnv)-DeleteLocalRef(jniEnv, setName);(*jniEnv)-DeleteLocalRef(jniEnv, getAge);return -2;}}if (toString NULL) {toString (*jniEnv)-GetMethodID(jniEnv, Person, toString,()Ljava/lang/String;);if (toString NULL) {(*jniEnv)-DeleteLocalRef(jniEnv, Person);(*jniEnv)-DeleteLocalRef(jniEnv, getName);(*jniEnv)-DeleteLocalRef(jniEnv, setName);(*jniEnv)-DeleteLocalRef(jniEnv, getAge);(*jniEnv)-DeleteLocalRef(jniEnv, setAge);return -2;}}return 1;
}
/**
* GetName 对应Person的getName方法
*/
void GetName() {if(Person NULL || getName NULL) {if(1 ! InitPerson()){return;}}//调用方法jstring jstr (*jniEnv)-CallObjectMethod(jniEnv, mPerson, getName);char* cstr (char*) (*jniEnv)-GetStringUTFChars(jniEnv,jstr, 0);__android_log_print(ANDROID_LOG_INFO, JNIMsg, getName ---- %s,cstr );//释放资源(*jniEnv)-ReleaseStringUTFChars(jniEnv, jstr, cstr);(*jniEnv)-DeleteLocalRef(jniEnv, jstr);
}
/**
* GetAge 对应Person的getName方法
*/
void GetAge() {if(Person NULL || getName NULL) {if(1 ! InitPerson()){return;}}//调用方法jint age (*jniEnv)-CallIntMethod(jniEnv, mPerson, getAge);__android_log_print(ANDROID_LOG_INFO, JNIMsg, getAge ---- %d,age );
}
/**
* SetName 对应Person的setName方法
*/
void SetName() {if(Person NULL || setName NULL) {if(1 ! InitPerson()){return;}}jstring jstr (*jniEnv)-NewStringUTF(jniEnv, Modify Name);//调用方法(*jniEnv)-CallVoidMethod(jniEnv, mPerson, setName,jstr);(*jniEnv)-DeleteLocalRef(jniEnv, jstr);
}
int age 20;
/**
* SetAge 对应Person的setAge方法
*/
void SetAge() {if(Person NULL || setAge NULL) {if(1 ! InitPerson()){return;}}//调用方法(*jniEnv)-CallVoidMethod(jniEnv, mPerson, setAge,age);
}
/**
* ToString 对应 Person 的 toString 方法 , 打印出相关信息
*/
void ToString() {if(Person NULL || toString NULL) {if(1 ! InitPerson()){return;}}jstring jstr NULL;char* cstr NULL;//调用方法jstr (*jniEnv)-CallObjectMethod(jniEnv, mPerson, toString);cstr (char*) (*jniEnv)-GetStringUTFChars(jniEnv,jstr, 0);__android_log_print(ANDROID_LOG_INFO, JNIMsg, C JNI toString ---- %s,cstr );(*jniEnv)-ReleaseStringUTFChars(jniEnv, jstr, cstr);(*jniEnv)-DeleteLocalRef(jniEnv, jstr);
}JNI 中创建 JAVA 对象的几种方式
1使用函数NewObject可以用来创建JAVA对象;
GetMethodID 能够取得构造方法的jmethodID, 如果传入的要取得的方法名称设为init就能够取得构造方法。
构造方法的方法返回值类型的签名始终为void
例
jclass clazz_date env-FindClass(java/util/Date);
jmethodID mid_date env-GetMethoID(clazz_date, init, ()V);
jobject now env-NewObject(clazz_date, mid_date);jmethodID mid _date_getTime env-GetMethodID(clazz_date, getTime , ())
jlong time env-CallLongMethod(now, mid_date_getTime);2使用函数AllocObject来创建JAVA对象
使用函数AllocObject可以根据传入的jclass创建一个JAVA对象便是他的状态是非初始化的在使用这个对象之前绝对要用CallNovirtualVoidMethod来调用该jclass的建构函数这样可以延迟构造函数的调用这一个部分用的很少在这里只做简单的说明。
jclass clazz_str env-FindClass(java/lang/String);
jmethodID methodID_str env-GetMethodID(clazz_str ,init, ([C)V);
//预先创建一个没有初始化的字符串
jobject string env-AllocObject(clazz_str);
//创建一个4个元素的的字符数组然后以“清”“原”“卓”“也”赋值
jcharArra arg env-NewCharArray(4);
env-SetCharArrayRegion(arg, 0, 4,L清原卓也);
// 呼叫构建子
env-CallNovirtualVoidMethod(string ,clazz_str,methodID,arg);
jclass clazz_this env-GetObjectClass(obj);
//这里假设这个对象的类有定义
static string STATIC_STR;
jfieldID fieldID_str env-GetStaticFieldID(clazz_this,STATIC_STR,Ljava/lang/String);
env-SetStaticObjectField(clazz_str, fieldID_str, string);3. JAVA字串 ----- C/C的字串
在JAVA中使用的字符串String对象是Unicode(UTF-16)码即每个字符不论是中文还是英文还是符号一个字符总是占两个字节
JAVA通过JNI接口可以将JAVA的字符串转换到C/C中的宽字符串wchar_t*或是传回一个 UTF-8的字符串char *到C/C反过来C/C可以通过一个宽字符串或是一个UTF-8编码的字符串来创建一个JAVA端的String对象。
GetStringChars 和 GetStringUTFChars
这两个函数用来取得与某个jstring对象相关的JAVA字符串分别可以取得UTF-16编码的宽字符串jchar*跟UTF8编码的字符串char*
const jchar* GetStringChars(jstring str, jboolean* copied)
const char* GetStringUTFChars(jstring str, jboolean *copied)第一个参数传入一个指向JAVA的String对象的jstring变量 第二个参数传入的是一个jboolean的指针
这两个函数分别都会有两个不同的动作
1开辟新的内存然后把JAVA中的String拷贝到这个内存中然后返回指向这个内存地址的指针。2直接返回指向JAVA的String的内存的指针这个时候千万不要改变这个内存的内容这将破坏String在Java中始终是常量这个原则
第二个参数是用来标示是否对Java的String对象进行了拷贝的。
如果传入的这个jboolean指针不是NULL则他会给该指针所指向的内存传入JNI_TRUE 或 JNI _FALSE标示是否进行了拷贝。
传入NULL表示不关心是否拷贝字符串它就不会给jboolean*指向的内存赋值。
使用这两个函数取得的字符串在不使用的时候要使用ReleaseStringChars/ReleaseStringUTFChars来释放拷贝的内存或是释放对JAVA的String对象的引用。
ReleaseStringChars(jstring jstr, const jchar* str)
ReleaseStringUTFChars(jstring jstr, const char* str)第一个参数指定一个jstring 变量即是要释放的本地字符串的来源 第二个参数就是要释放的本地字符串
GetStringCritical
为了增加直接传回指向JAVA字符串的指针的可能性而不是拷贝JDK1.2出来了新的函数GetStringCritical/ReleaseStringCritical
const jchar* GetStringCritical(jstring str, jboolean* copied);
void ReleaseStringCritical(jstring jstr, const jchar* str);在GetStringCritical/ReleaseStringCritical之间是一个关键区在这关键区之中绝对不能呼叫JNI的其它函数和会造成当前线程中断或是会让当前线程等待的任何本地代码否则将造成关键区代码执行期间垃圾回收器停止动作任何触发垃圾回收器的线程也会暂停其他的触发垃圾回收器的线程不能前进直到当前线程结束而激活垃圾回收器
在关键区千万不要出现中断操作或是在JVM中分配任何新对象否则会造成JVM死锁。
虽说这个函数会增加直接传回指向JAVA字符串的指针的可能性不过还是会根据情况传回拷贝过的字符串
不支持GetStringUTFCritical没有这样的函数因为JAVA字符串用的是UTF-16要转换成UTF-8编码的字符串始终需要进行一次拷贝所以没有这样的函数。
GetStringRegion 和 GetStringUTFRegion
JAVA1.2F出来的函数这个函数的动作是把JAVA字符串的内容直接拷贝到C/C的字符数组中在呼叫这个函数之前必须有一个C/C分配出来的字符串然后传入到这个函数中进行字符串的拷贝。
由于C/C分配内存开销相对小而且JAVA中的String内容拷贝的开销可以忽略更好的一点是些函数不会分配内存不会抛出OutOfMemoryError异常
// 拷贝JAVA字符串并以UTF-8编码传入buffer
GetStringUTFRegion(jstring str , jsize start, jsize len, char* buffer);
// 拷贝JAVA字符串并以UTF-16编码传入buffer
GetStringRegion(jstring str , jsize start, jsize len, char* buffer);其他的字符串函数
jstring NewString(const jchar* str , jsize len);
jstring NewStringUTF(const char* str);
jsize GetStringLength(jstring str);
jsize GetStringUTFLength(jstring str)C/C 结构体和J ava对象的转换
直接参考该文https://blog.csdn.net/tkwxty/article/details/103348031
但这种方法是一种非常简单暴力的方法只适合特定的简单数据类型如果是复杂的对象还是不能这样做。该方法可以作为一种拓展思路。这里就不拿出来整理了。