一.访问静态字段

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文件拷贝到Android工程的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<ReturnValueType>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, "<init>", "([C)V");
if (cid == NULL) {
LOGE("GetMethodID <init> 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<ReturnValueType>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的 
优化。

Android jni/ndk编程三:native访问java的更多相关文章

  1. Android JNI&NDK编程小结及建议

    前言 由于网上关于JNI/NDK相关的知识点介绍的比较零散而且不具备参照性,所以写了这篇JNI/NDK笔记,便于作为随时查阅的工具类型的文章,本文主要的介绍了在平时项目中常用的命令.JNI数据类型.签 ...

  2. Android jni/ndk编程二:jni数据类型转换(primitive,String,array)

    一.数据类型映射概述 从我们开始jni编程起,就不可能避开函数的参数与返回值的问题.java语言的数据类型和c/c++有很多不同的地方,所以我们必须考虑当在java层调用c/c++函数时,怎么正确的把 ...

  3. Android jni/ndk编程五:jni异常处理

    在Java的编程中,我们经常会遇到各种的异常,也会处理各种的异常.处理异常在java中非常简单,我们通常会使用try-catch-finally来处理,也可以使用throw简单抛出一个异常.那么在jn ...

  4. Android jni/ndk编程四:jni引用类型

    一.JNI引用类型 JNI支持三种类型的 opaque reference:local references, global references,和weak global references,下面 ...

  5. Android之NDK编程(JNI)

    转自:http://www.cnblogs.com/xw022/archive/2011/08/18/2144621.html NDK编程入门--C回调JAVA方法   一.主要流程 1.  新建一个 ...

  6. android Jni NDK开发环境搭建及其简单实例的编写

    android  Jni  NDK开发环境搭建及其简单实例的编写 由于工作需要,需要采用开发想要的JNI,由于之前没有接触过安卓的开发,所以更加网上的帖子,学习了下.遇到了些问题,然后总结下学习过程中 ...

  7. Android Studio NDK编程初探

    继上一篇学习了如何使用NDK编译FFMPEG后,接下来就是要学习如何在Android Studio中使用了. 经过参考和一系列的摸索,记录下具体步骤. 创建C++ Support的Android St ...

  8. Android Studio JNI/NDK 编程简介(一)

    首先说一下概念及相关的东西: JNI : JNI是Java Native Interface的缩写,它提供了若干的API实现了Java和其他语言的通信(主要是C&C++).从Java1.1开始 ...

  9. 一天掌握Android JNI本地编程 快速入门

    一.JNI(Java Native Interface)        1.什么是JNI:               JNI(Java Native Interface):java本地开发接口   ...

随机推荐

  1. 第九章、import 和from ...import

    目录 第九章.import 和from ...import 一.import和 from ...import ... 二.import模块名 第九章.import 和from ...import 一. ...

  2. 如何解决Win10系统更新显示0x80080300代码的错误?

    Win10系统自推出以来就不断的在完善更新,其越来越丰富的功能也吸引了越来越多的用户.好系统Win10系统:https://www.vkebao.com/os/index_2.html但最近有用户反映 ...

  3. Win10系统如何利用蓝牙设置动态锁?

    很多小伙伴都会有这样的经历,出门之后没走多远,却已然忘记是否锁门,有强迫症的人就会重新返回查看,以确保门是否反锁. 我们在使用电脑时也是这样,遇到事情要临时离开,却忘记是否锁屏,再返回来就耽误时间了. ...

  4. 网络基础篇之NAT(原理)

    一.NAT的产生 由于网络的飞速发展和网络应用的极速增多,致使IPv4可用地址空间逐渐枯竭.尽管IPv6可以在根本上解决地址枯竭问题,但IPv4发展到IPv6还需要一个过渡,而这便产生了NAT. 二. ...

  5. C语言求π的方法

    #include <stdio.h> #include <math.h> int main() { int r; double PI,s; scanf("%d&quo ...

  6. jsp学习——九大内置对象

    JSP一共有九个内置对象,分别为:request.response.session.application.out.pagecontext.config.page.exception 博客:JSP的九 ...

  7. Linux之yum软件管理

    YUM yum = Yellow dog Updater, Modified主要功能是更方便的添加/删除/更新RPM包.它能自动解决包的倚赖性问题. 它能便于管理大量系统的更新问题 yum特点 *可以 ...

  8. 如何阻止<a>标签默认行为和表单提交

    阻止<a>标签默认行为 方式一 (通过return false) <!DOCTYPE html> <html> <head> <meta char ...

  9. 解决power designer 不能自动生成注释 commont 的解决办法只需要3步:

    解决power designer 不能自动生成注释的解决办法只需要3步: 一.快捷键 Ctrl+Shift+X 打开脚本编辑器:(快捷键不能执行的话可以从这个路径执行:Tools --> Exc ...

  10. WCF概述

    Tips:概念性的东西仅助理解,可以略过 概述 1.SOA概述 1).从三个问题开始 SOA是什么——面向服务架构.一种编程模式.一种架构模式.它将应用程序分成不同功能(服务)单元,再通过服务之间的接 ...