博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android jni/ndk编程三:native访问java
阅读量:5070 次
发布时间:2019-06-12

本文共 18437 字,大约阅读时间需要 61 分钟。

一.访问静态字段

Java层的field和method,不管它是public,还是package、private和protected,从 

JNI都可以访问到,Java面向语言的封装性不见了。 
静态字段和非静态的字段访问方式不同,jni规范提供了一系列带static标示的访问静态字段的函数:

jobject     (*GetStaticObjectField)(JNIEnv*, jclass, jfieldID);    jboolean    (*GetStaticBooleanField)(JNIEnv*, jclass, jfieldID);    jbyte       (*GetStaticByteField)(JNIEnv*, jclass, jfieldID); jchar (*GetStaticCharField)(JNIEnv*, jclass, jfieldID); jshort (*GetStaticShortField)(JNIEnv*, jclass, jfieldID); jint (*GetStaticIntField)(JNIEnv*, jclass, jfieldID); jlong (*GetStaticLongField)(JNIEnv*, jclass, jfieldID); jfloat (*GetStaticFloatField)(JNIEnv*, jclass, jfieldID) __NDK_FPABI__; jdouble (*GetStaticDoubleField)(JNIEnv*, jclass, jfieldID) __NDK_FPABI__; void (*SetStaticObjectField)(JNIEnv*, jclass, jfieldID, jobject); void (*SetStaticBooleanField)(JNIEnv*, jclass, jfieldID, jboolean); void (*SetStaticByteField)(JNIEnv*, jclass, jfieldID, jbyte); void (*SetStaticCharField)(JNIEnv*, jclass, jfieldID, jchar); void (*SetStaticShortField)(JNIEnv*, jclass, jfieldID, jshort); void (*SetStaticIntField)(JNIEnv*, jclass, jfieldID, jint); void (*SetStaticLongField)(JNIEnv*, jclass, jfieldID, jlong); void (*SetStaticFloatField)(JNIEnv*, jclass, jfieldID, jfloat) __NDK_FPABI__; void (*SetStaticDoubleField)(JNIEnv*, jclass, jfieldID, jdouble) __NDK_FPABI__;

访问流程:

  1. 获得java层的类:jclass cls = (*env)->GetObjectClass(env, obj);
  2. 获得字段的ID:jfieldID fid = (*env)->GetStaticFieldID(env, cls, “s”, “Ljava/lang/String;”);
  3. 获得字段的值:jstring jstr = (*env)->GetStaticObjectField(env, cls, fid);
  4. 设置字段的值:(*env)->SetStaticObjectField(env, cls, fid, jstr);

按照以上的流程,参照上面访问静态字段的函数定义,写如下代码:

void  native_accessJava(JNIEnv * env, jobject obj){    LOGE("lstr:native_accessJava");    //1. 获得java层的类:jclass cls = (*env)->GetObjectClass(env, obj); jclass cls = (*env)->GetObjectClass(env, obj); //2. 获得字段的ID:jfieldID fid = (*env)->GetStaticFieldID(env, cls, "s", "Ljava/lang/String;"); jfieldID fid = (*env)->GetStaticFieldID(env, cls, "s", "Ljava/lang/String;"); if (fid == NULL) { LOGE("get feild id error"); return; /* failed to find the field */ } //3. 获得字段的值:jstring jstr = (*env)->GetStaticObjectField(env, cls, fid); jstring jstr = (*env)->GetStaticObjectField(env, cls, fid); LOGE("lstr:native_accessJava"); const char * lstr = (*env)->GetStringUTFChars(env,jstr,NULL); LOGE("lstr: %s",lstr); (*env)->ReleaseStringUTFChars(env,jstr,lstr); //4. 设置字段的值:(*env)->SetStaticObjectField(env, cls, fid, jstr); jstr = (*env)->NewStringUTF(env, "jni set"); if (jstr == NULL) { return; /* out of memory */ } (*env)->SetStaticObjectField(env, cls, fid, jstr); }

注册方法的数组:

static JNINativeMethod gMethods[] = {  {
"sayHello", "([I)I", (void *)native_sayHello}, {
"arrayTry","([Ljava/lang/String;)[Ljava/lang/String;",(void *)native_arrayTry}, { "accessJava","()V",(void *)native_accessJava}, };

java中访问的代码:

public class MainActivity extends AppCompatActivity { TextView textView = null; static String s = "java str"; static { System.loadLibrary("hello"); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); textView = (TextView) findViewById(R.id.text); accessJava(); textView.setText(s); } public native int sayHello(int []arr); public native String[] arrayTry(String [] arr); public native void accessJava(); }

在jni代码所在目录执行adk-build命令,把编译生成的libhello.so文件拷贝到工程的jniLibs目录下,运行android程序即可看到现象。

二.访问实例字段

有了访问静态字段的经历,在去写访问实例字段的代码就简单多了,这里总结下使用流程:

  1. 获得java层的类:jclass cls = (*env)->GetObjectClass(env, obj);
  2. 获得字段的ID:jfieldID fid = (*env)->GetFieldID(env, cls, “ss”, “Ljava/lang/String;”);
  3. 获得字段的值:jstring jstr = (*env)->GetObjectField(env, obj, fid);
  4. 设置字段的值:(*env)->SetObjectField(env, obj, fid, jstr);

在写代码之前,先看一下jni.h中定义的访问实例字段的函数:

jfieldID    (*GetFieldID)(JNIEnv*, jclass, const char*, const char*);    jobject     (*GetObjectField)(JNIEnv*, jobject, jfieldID); jboolean (*GetBooleanField)(JNIEnv*, jobject, jfieldID); jbyte (*GetByteField)(JNIEnv*, jobject, jfieldID); jchar (*GetCharField)(JNIEnv*, jobject, jfieldID); jshort (*GetShortField)(JNIEnv*, jobject, jfieldID); jint (*GetIntField)(JNIEnv*, jobject, jfieldID); jlong (*GetLongField)(JNIEnv*, jobject, jfieldID); jfloat (*GetFloatField)(JNIEnv*, jobject, jfieldID) __NDK_FPABI__; jdouble (*GetDoubleField)(JNIEnv*, jobject, jfieldID) __NDK_FPABI__; void (*SetObjectField)(JNIEnv*, jobject, jfieldID, jobject); void (*SetBooleanField)(JNIEnv*, jobject, jfieldID, jboolean); void (*SetByteField)(JNIEnv*, jobject, jfieldID, jbyte); void (*SetCharField)(JNIEnv*, jobject, jfieldID, jchar); void (*SetShortField)(JNIEnv*, jobject, jfieldID, jshort); void (*SetIntField)(JNIEnv*, jobject, jfieldID, jint); void (*SetLongField)(JNIEnv*, jobject, jfieldID, jlong); void (*SetFloatField)(JNIEnv*, jobject, jfieldID, jfloat) __NDK_FPABI__; void (*SetDoubleField)(JNIEnv*, jobject, jfieldID, jdouble) __NDK_FPABI__;

可以看到访问实例字段的函数和访问静态字段的函数在名字上就有区别,而且一定要注意的是,访问实例字段函数的第三个参数是jobject,是一个对象,而访问静态字段的第三个参数是jclass,是一个类。

我们使用上面给出的函数和我们总结的使用流程写如下代码:

void  native_accessinstanceJava(JNIEnv * env, jobject obj){    LOGE("lstr:native_accessinstanceJava");    //1. 获得java层的类:jclass cls = (*env)->GetObjectClass(env, obj); jclass cls = (*env)->GetObjectClass(env, obj); //2. 获得字段的ID:jfieldID fid = (*env)->GetFieldID(env, cls, "ss", "Ljava/lang/String;"); jfieldID fid = (*env)->GetFieldID(env, cls, "ss", "Ljava/lang/String;"); if (fid == NULL) { LOGE("get feild id error"); return; /* failed to find the field */ } //3. 获得字段的值:jstring jstr = (*env)->GetObjectField(env, cls, fid); jstring jstr = (*env)->GetObjectField(env, obj, fid); const char * lstr = (*env)->GetStringUTFChars(env,jstr,NULL); LOGE("lstr: %s",lstr); (*env)->ReleaseStringUTFChars(env,jstr,lstr); //4. 设置字段的值:(*env)->SetObjectField(env, cls, fid, jstr); jstr = (*env)->NewStringUTF(env, "jni set"); if (jstr == NULL) { return; /* out of memory */ } (*env)->SetObjectField(env, obj, fid, jstr); }

注册方法的数组:

static JNINativeMethod gMethods[] = {  {
"sayHello", "([I)I", (void *)native_sayHello}, {
"arrayTry","([Ljava/lang/String;)[Ljava/lang/String;",(void *)native_arrayTry}, { "accessJava","()V",(void *)native_accessJava}, { "accessinstanceJava","()V",(void *)native_accessinstanceJava}, };

JNI_OnLoad等方法请参考之前的博客。 

java层调用很非常简单,这里就不贴了。

三.访问静态方法

静态方法的访问总结为两步: 

• 首先通过GetStaticMethodID在给定类中查找方法 
如:jmethodID mid = (*env)->GetStaticMethodID(env,cls,”changeStr”,”()V”); 
• 通过CallStaticMethod调用 
如:(*env)->CallStaticVoidMethod(env, cls, mid); 
jni中定义的访问静态方法的函数有如下一些:

jmethodID   (*GetStaticMethodID)(JNIEnv*, jclass, const char*, const char*);    jobject     (*CallStaticObjectMethod)(JNIEnv*, jclass, jmethodID, ...);    jobject     (*CallStaticObjectMethodV)(JNIEnv*, jclass, jmethodID, va_list);    jobject     (*CallStaticObjectMethodA)(JNIEnv*, jclass, jmethodID, jvalue*);    jboolean    (*CallStaticBooleanMethod)(JNIEnv*, jclass, jmethodID, ...);    jboolean    (*CallStaticBooleanMethodV)(JNIEnv*, jclass, jmethodID,va_list);    jboolean    (*CallStaticBooleanMethodA)(JNIEnv*, jclass, jmethodID, jvalue*);    jbyte       (*CallStaticByteMethod)(JNIEnv*, jclass, jmethodID, ...);    jbyte       (*CallStaticByteMethodV)(JNIEnv*, jclass, jmethodID, va_list);    jbyte       (*CallStaticByteMethodA)(JNIEnv*, jclass, jmethodID, jvalue*);    jchar       (*CallStaticCharMethod)(JNIEnv*, jclass, jmethodID, ...); jchar (*CallStaticCharMethodV)(JNIEnv*, jclass, jmethodID, va_list); jchar (*CallStaticCharMethodA)(JNIEnv*, jclass, jmethodID, jvalue*); jshort (*CallStaticShortMethod)(JNIEnv*, jclass, jmethodID, ...); jshort (*CallStaticShortMethodV)(JNIEnv*, jclass, jmethodID, va_list); jshort (*CallStaticShortMethodA)(JNIEnv*, jclass, jmethodID, jvalue*); jint (*CallStaticIntMethod)(JNIEnv*, jclass, jmethodID, ...); jint (*CallStaticIntMethodV)(JNIEnv*, jclass, jmethodID, va_list); jint (*CallStaticIntMethodA)(JNIEnv*, jclass, jmethodID, jvalue*); jlong (*CallStaticLongMethod)(JNIEnv*, jclass, jmethodID, ...); jlong (*CallStaticLongMethodV)(JNIEnv*, jclass, jmethodID, va_list); jlong (*CallStaticLongMethodA)(JNIEnv*, jclass, jmethodID, jvalue*); jfloat (*CallStaticFloatMethod)(JNIEnv*, jclass, jmethodID, ...) __NDK_FPABI__; jfloat (*CallStaticFloatMethodV)(JNIEnv*, jclass, jmethodID, va_list) __NDK_FPABI__; jfloat (*CallStaticFloatMethodA)(JNIEnv*, jclass, jmethodID, jvalue*) __NDK_FPABI__; jdouble (*CallStaticDoubleMethod)(JNIEnv*, jclass, jmethodID, ...) __NDK_FPABI__; jdouble (*CallStaticDoubleMethodV)(JNIEnv*, jclass, jmethodID, va_list) __NDK_FPABI__; jdouble (*CallStaticDoubleMethodA)(JNIEnv*, jclass, jmethodID, jvalue*) __NDK_FPABI__; void (*CallStaticVoidMethod)(JNIEnv*, jclass, jmethodID, ...); void (*CallStaticVoidMethodV)(JNIEnv*, jclass, jmethodID, va_list); void (*CallStaticVoidMethodA)(JNIEnv*, jclass, jmethodID, jvalue*);

结合上面总结的流程和jni.h中定义的函数,写如下测试代码: 

代码功能:调用java层的静态方法,修改静态字段的值,把修改后的字段的值使用TextView显示出来。

void  native_staticMethod(JNIEnv * env, jobject obj){    LOGE("native_staticMethod");    //1.获得类中方法id    jclass cls = (*env)->GetObjectClass(env, obj); jmethodID mid = (*env)->GetStaticMethodID(env,cls,"changeStr","()V"); if (mid == NULL) { LOGE("GetStaticMethodID error"); return; /* method not found */ } LOGE("GetStaticMethodID sucess"); //2.调用CallStatic
Method函数调用对应函数. (*env)->CallStaticVoidMethod(env, cls, mid); }

注册方法的数组:

static JNINativeMethod gMethods[] = {  {
"sayHello", "([I)I", (void *)native_sayHello}, {
"arrayTry","([Ljava/lang/String;)[Ljava/lang/String;",(void *)native_arrayTry}, { "accessJava","()V",(void *)native_accessJava}, { "accessinstanceJava","()V",(void *)native_accessinstanceJava}, { "staticMethod","()V",(void *)native_staticMethod}, };

添加了staticMethod方法的注册。 

java层的调用:

public class MainActivity extends AppCompatActivity { TextView textView = null; static String s = "java str"; String ss = "instance str"; static { System.loadLibrary("hello"); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); textView = (TextView) findViewById(R.id.text); staticMethod(); textView.setText(s); } public native int sayHello(int []arr); public native String[] arrayTry(String [] arr); public native void accessJava(); public native void accessinstanceJava(); public native void staticMethod(); public static void changeStr(){ s = "chang str"; } }

四.访问实例方法

访问实例方法与访问静态方法类似,要注意的主要是:实例方法是属于对象jobject的,而静态方法是属于类的。

4.1普通实例方法

访问普通的实例方法的步骤还是总结为两步: 

• 首先通过GetMethodID在给定类中查找方法 
如:jmethodID mid = (*env)->GetMethodID(env,cls,”changeStr”,”()V”); 
• 通过CallMethod调用 
如:(*env)->CallStaticVoidMethod(env, obj, mid);

jni.h中定义的访问实例方法的相关函数有:

jmethodID   (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);    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, ...) __NDK_FPABI__; jfloat (*CallFloatMethodV)(JNIEnv*, jobject, jmethodID, va_list) __NDK_FPABI__; jfloat (*CallFloatMethodA)(JNIEnv*, jobject, jmethodID, jvalue*) __NDK_FPABI__; jdouble (*CallDoubleMethod)(JNIEnv*, jobject, jmethodID, ...) __NDK_FPABI__; jdouble (*CallDoubleMethodV)(JNIEnv*, jobject, jmethodID, va_list) __NDK_FPABI__; jdouble (*CallDoubleMethodA)(JNIEnv*, jobject, jmethodID, jvalue*) __NDK_FPABI__; void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...); void (*CallVoidMethodV)(JNIEnv*, jobject, jmethodID, va_list); void (*CallVoidMethodA)(JNIEnv*, jobject, jmethodID, jvalue*); jobject (*CallNonvirtualObjectMethod)(JNIEnv*, jobject, jclass,jmethodID, ...); jobject (*CallNonvirtualObjectMethodV)(JNIEnv*, jobject, jclass, jmethodID, va_list); jobject (*CallNonvirtualObjectMethodA)(JNIEnv*, jobject, jclass, jmethodID, jvalue*); jboolean (*CallNonvirtualBooleanMethod)(JNIEnv*, jobject, jclass,jmethodID, ...); jboolean (*CallNonvirtualBooleanMethodV)(JNIEnv*, jobject, jclass,jmethodID, va_list); jboolean (*CallNonvirtualBooleanMethodA)(JNIEnv*, jobject, jclass, jmethodID, jvalue*); jbyte (*CallNonvirtualByteMethod)(JNIEnv*, jobject, jclass, jmethodID, ...); jbyte (*CallNonvirtualByteMethodV)(JNIEnv*, jobject, jclass,jmethodID, va_list); jbyte (*CallNonvirtualByteMethodA)(JNIEnv*, jobject, jclass,jmethodID, jvalue*); jchar (*CallNonvirtualCharMethod)(JNIEnv*, jobject, jclass, jmethodID, ...); jchar (*CallNonvirtualCharMethodV)(JNIEnv*, jobject, jclass, jmethodID, va_list); jchar (*CallNonvirtualCharMethodA)(JNIEnv*, jobject, jclass,jmethodID, jvalue*); jshort (*CallNonvirtualShortMethod)(JNIEnv*, jobject, jclass,jmethodID, ...); jshort (*CallNonvirtualShortMethodV)(JNIEnv*, jobject, jclass,jmethodID, va_list); jshort (*CallNonvirtualShortMethodA)(JNIEnv*, jobject, jclass, jmethodID, jvalue*); jint (*CallNonvirtualIntMethod)(JNIEnv*, jobject, jclass, jmethodID, ...); jint (*CallNonvirtualIntMethodV)(JNIEnv*, jobject, jclass, jmethodID, va_list); jint (*CallNonvirtualIntMethodA)(JNIEnv*, jobject, jclass, jmethodID, jvalue*); jlong (*CallNonvirtualLongMethod)(JNIEnv*, jobject, jclass, jmethodID, ...); jlong (*CallNonvirtualLongMethodV)(JNIEnv*, jobject, jclass, jmethodID, va_list); jlong (*CallNonvirtualLongMethodA)(JNIEnv*, jobject, jclass, jmethodID, jvalue*); jfloat (*CallNonvirtualFloatMethod)(JNIEnv*, jobject, jclass, jmethodID, ...) __NDK_FPABI__; jfloat (*CallNonvirtualFloatMethodV)(JNIEnv*, jobject, jclass, jmethodID, va_list) __NDK_FPABI__; jfloat (*CallNonvirtualFloatMethodA)(JNIEnv*, jobject, jclass, jmethodID, jvalue*) __NDK_FPABI__; jdouble (*CallNonvirtualDoubleMethod)(JNIEnv*, jobject, jclass,jmethodID, ...) __NDK_FPABI__; jdouble (*CallNonvirtualDoubleMethodV)(JNIEnv*, jobject, jclass,jmethodID, va_list) __NDK_FPABI__; jdouble (*CallNonvirtualDoubleMethodA)(JNIEnv*, jobject, jclass, jmethodID, jvalue*) __NDK_FPABI__; void (*CallNonvirtualVoidMethod)(JNIEnv*, jobject, jclass, jmethodID, ...); void (*CallNonvirtualVoidMethodV)(JNIEnv*, jobject, jclass, jmethodID, va_list); void (*CallNonvirtualVoidMethodA)(JNIEnv*, jobject, jclass,jmethodID, jvalue*);

4.2被子类覆盖的父类方法

我们看到了很多Nonvirtual方法,这是jni提供用来访问被子类赋给的父类的方法的,使用步骤如下: 

调用被子类覆盖的父类方法: JNI支持用CallNonvirtualMethod满足这类需求: 
• GetMethodID获得method ID 
• 调用CallNonvirtualVoidMethod, CallNonvirtualBooleanMethod 
上述,等价于如下Java语言的方式: 
super.f(); 
CallNonvirtualVoidMethod可以调用构造函数

4.3构造函数

你可以像调用实例方法一样,调用构造方法,只是此时构造函数的名称叫做””.

综合上面三个知识点,我们设计如下代码时间这些知识: 

1.在c函数中调用String类的构造函数新建一个字符串对象。 
2.调用java的实例方法,传入我们1中构建的字符串对象,修改TextView的内容。 
代码如下:

void  native_instanceMethod(JNIEnv * env, jobject obj){    LOGE("native_instanceMethod");    //1.使用String类的构造函数构造String    //1.1找到String类 jclass stringClass = (*env)->FindClass(env, "java/lang/String"); if (stringClass == NULL) { LOGE("FindClass error"); return; } //1.2找到String类的构造函数 jmethodID cid = (*env)->GetMethodID(env, stringClass, "
", "([C)V"); if (cid == NULL) { LOGE("GetMethodID
error"); return; /* exception thrown */ } //1.3创建字符数组 jint len = 10; jcharArray elemArr = (*env)->NewCharArray(env, len); if (elemArr == NULL) { LOGE("NewCharArray error"); return; /* exception thrown */ } jchar java_char[]={ 97,98,99,100,101,102,103,104,105,106};//abcdefghij //1.4设置字符数组 (*env)->SetCharArrayRegion(env, elemArr, 0, len, java_char); //1.5 创建一个字符串对象 jstring result = (*env)->NewObject(env, stringClass, cid, elemArr); //2.获得类中方法id jclass cls = (*env)->GetObjectClass(env, obj); jmethodID mid = (*env)->GetMethodID(env,cls,"changeTextView","(Ljava/lang/String;)V"); if (mid == NULL) { LOGE("GetMethodID error"); return; /* method not found */ } LOGE("GetMethodID sucess"); //2.调用Call
Method函数调用对应函数. (*env)->CallVoidMethod(env, obj, mid,result); }

注册方法的数组:

static JNINativeMethod gMethods[] = {  {
"sayHello", "([I)I", (void *)native_sayHello}, {
"arrayTry","([Ljava/lang/String;)[Ljava/lang/String;",(void *)native_arrayTry}, { "accessJava","()V",(void *)native_accessJava}, { "accessinstanceJava","()V",(void *)native_accessinstanceJava}, { "staticMethod","()V",(void *)native_staticMethod}, { "instanceMethod","()V",(void *)native_instanceMethod}, };

java层调用:

static JNINativeMethod gMethods[] = {  {
"sayHello", "([I)I", (void *)native_sayHello}, {
"arrayTry","([Ljava/lang/String;)[Ljava/lang/String;",(void *)native_arrayTry}, { "accessJava","()V",(void *)native_accessJava}, { "accessinstanceJava","()V",(void *)native_accessinstanceJava}, { "staticMethod","()V",(void *)native_staticMethod}, { "instanceMethod","()V",(void *)native_instanceMethod}, };

访问实例方法的实验到此结束。

五.性能与优化

5.1缓存Field 和 Method IDs

每次获得Field和Method IDS都比较耗时,如果我们需要多次获取他们,那就应该把它们缓存起来,这样以后用的时候就可以直接用了,从而节约了时间。 

缓存的方式可以使用局部static字段缓存,也可以在类的初始化时,一次性缓存好全部的Field 和 Method IDs。 
上述第一次使用缓存的方式,每次都有与NULL的判断,并且可能有一个无害的竞争条件。 
而初始化类时,同时初始化JNI层对该类成员的缓存,可以弥补上述缺憾。

5.2影响jni回调性能的因素

首先比较Java/native和Java/Java 

前者因下述原因可能会比后者慢: 
• Java/native与Java/Java的调用约定不同. 所以,VM必须在调用前,对参数和调用 
栈做特殊准备 
• 常用的优化技术是内联. 相比Java/Java调用,Java/native创建内联方法很难 
粗略估计:执行一个Java/native调用要比Java/Java调用慢2-3倍. 也可能有一些VM实 
现,Java/native调用性能与Java/Java相当。(此种虚拟机,Java/native使用Java/Java 
相同的调用约定)。 
其次比较native/Java与Java/Java 
native/Java调用效率可能与Java/Java有10倍的差距,因为VM一般不会做Callback的 
优化。 

转载于:https://www.cnblogs.com/chenxibobo/p/6895472.html

你可能感兴趣的文章
C#设置鼠标在控件上面时,改变光标形状
查看>>
rocketmq消费队列代码
查看>>
LogHelper拾遗
查看>>
《当裸辞的程序猿遇上最冷季九》——累觉不爱,暂时停更
查看>>
总览:SpringCloud基础结构
查看>>
(WIP) DPDK理论学习(by quqi99)
查看>>
boost - 正则表达式xpressive
查看>>
Java学习笔记之接口和抽象类
查看>>
解决使用MasterPage后,Page.FindControl方法找不到指定控件的问题
查看>>
Spring与freemarker集成利用freemarker静态化页面
查看>>
spring 实现原理
查看>>
spark:neither spark.yarn.jars not spark.yarn.archive is set
查看>>
Win7有多条隧道适配器的原因及关闭方法
查看>>
【cs229-Lecture9】经验风险最小化
查看>>
small test on 5.29 night T1
查看>>
Cheatsheet: 2013 12.01 ~ 12.16
查看>>
Cheatsheet: 2017 10.01 ~ 12.31
查看>>
【Python】Python-skier游戏[摘自.与孩子一起学编程]
查看>>
HDU - 1816 Get Luffy Out *(二分 + 2-SAT)
查看>>
C语言如何实现C++中对象属性和方法
查看>>