一.访问静态字段

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. 【Swift后台】目录

    背景介绍 环境安装

  2. php迭代器Iterator接口

    以前也看过迭代器Iterator接口,感觉不如yied好用,因此实际工作中并没有用到过. 今天看了一篇网上的博客(https://www.cnblogs.com/wwjchina/p/7723499. ...

  3. 如何使windows7的默认共享可以被访问[转载]

        因为UAC的存在, 如果使用windows 7 的默认共享,比如 \abcc$ ,会被提示 无权限错误. 为了方便在局域网共享文件,找到了这个方法. Open the registry edi ...

  4. PHP的八种数据类型

    PHP 支持8种基本的数据类型. 四种标量类型: boolean (布尔型) integer (整型) float (浮点型, 也称作 double) string (字符串) 两种复合类型: arr ...

  5. ISO/IEC 15444-12 MP4 封装格式标准摘录 5

    目录 Segments Segment Type Box Segment Index Box Subsegment Index Box Producer Reference Time Box Supp ...

  6. IntelliJ IDEA安装后几个重要的目录及配置文件讲解

    本文大概记录了IntelliJ IDEA安装之后比较重要的目录和几个核心文件 重要的安装目录 安装完之后的bin目录大致如下 IntelliJ IDEA 的安装目录并不复杂,上图为最常改动的 bin ...

  7. Echarts 饼状图 字体重叠问题

    原理:设置最小扇形的大小,把他撑起来 在 series 里 使用 minAngle: 38, //最小的扇区角度(0 ~ 360),用于防止某个值过小导致扇区太小影响交互 角度自己调好就可以了 个人笔 ...

  8. grub命令行和配置文件配置配置信息

    一.grub简介 GNU GRUB(简称“GRUB”)是一个来自GNU项目的启动引导程序.GRUB是多启动规范的实现,它允许用户可以在计算机内同时拥有多个操作系统,并在计算机启动时选择希望运行的操作系 ...

  9. 报表开发神器!DevExpress Reporting v19.1:WinForms平台新功能

    行业领先的.NET界面控件DevExpress Reporting全新发布了v19.1版本,本文主要为大家介绍WinForms.ASP.Net Core平台.Visual Studio报表设计器中发布 ...

  10. AJAX 请求完成时执行函数。Ajax 事件。

    ajaxComplete(callback) 概述 AJAX 请求完成时执行函数.Ajax 事件. XMLHttpRequest 对象和设置作为参数传递给回调函数.大理石直角尺 参数 callback ...