前言
JNI允许本地方法访问Java对象的域和调用方法。今天就介绍一下放问java方法和对象的域。
记录一下,方便自己查阅。
正文
JNI访问对象域和方法,主要涉及如下几步骤:
-
获取到对象域的jfieldID或jmethodID
-
通过jfieldID获取对象域的值或者通过jmethodID调用对应的方法。
-
对于对象域,还可以通过jfieldID改变值。
下面单独介绍使用。
访问方法
在介绍前,主要注意带有static的方法跟没有static方法的是有区别的。
# Hello.java中 # 非静态 public int add(int x, int y) { return x + y; } # 非静态 public int sub(int x, int y) { return x - y; } # 静态 public static int multiply(int x, int y) { return x * y; }
第一步
静态和非静态jmethodID的获取方法存在不一,JNI中有区分的。
非静态方法
jmethodID addMethodID = env->GetMethodID(clazz, "add", "(II)I"); jmethodID subMethodID = env->GetMethodID(clazz, "sub", "(II)I");
静态方法
jmethodID multiplyMethodId = env->GetStaticMethodID(clazz, "multiply", "(II)I");
PS: GetxxxMethodID()中是否有static取决于方法中是否有static声明。
看完到上面,你或许跟我一样的想法,static方法是属于类,也属于对象的,那如果我不用JNI定义的static方法获取jmethodID呢?
我尝试了一下,编译是OK的,但运行是异常了。
JNI DETECTED ERROR IN APPLICATION: JNI CallIntMethodV called with pending exception java.lang.NoSuchMethodError: no non-static method "Lcom/biumall/dynamic/one/Hello;.multiply(II)I"
异常中也告诉我们 no non-static method "Lcom/biumall/dynamic/one/Hello;.multiply(II)I"(multiply是静态类),意思就是需要使用静态的方法访问他。
第二步
JNI的函数中可以通过jmethodID进行调用Java的方法。
非静态方法
if(NULL != addMethodID){ count = env->CallIntMethod(object, addMethodID, x, y); } if(NULL != subMethodID){ count = env->CallIntMethod(object, subMethodID, x, y); }
CallIntMethod()表示调用非静态的返回值为int的addMethodID或subMethodID方法。
jni.h中还有其他返回类型的方法。
jobject (*CallObjectMethod)(JNIEnv*, jobject, jmethodID, ...); jboolean (*CallBooleanMethod)(JNIEnv*, jobject, jmethodID, ...); jbyte (*CallByteMethod)(JNIEnv*, jobject, jmethodID, ...); jchar (*CallCharMethod)(JNIEnv*, jobject, jmethodID, ...); jshort (*CallShortMethod)(JNIEnv*, jobject, jmethodID, ...); jint (*CallIntMethod)(JNIEnv*, jobject, jmethodID, ...); jlong (*CallLongMethod)(JNIEnv*, jobject, jmethodID, ...); jfloat (*CallFloatMethod)(JNIEnv*, jobject, jmethodID, ...); jdouble (*CallDoubleMethod)(JNIEnv*, jobject, jmethodID, ...); void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...);
静态方法
if(NULL == multiplyMethodId){ count = env->CallStaticIntMethod(clazz, multiplyMethodId, x, y); }
CallStaticIntMethod()表示调用非静态的返回值为int的multiplyMethodId方法。
需要注意的,因为是static方法,所以第二个参数传入的类引用!(重点)
jni.h中还有其他返回类型的方法。
jobject (*CallStaticObjectMethod)(JNIEnv*, jclass, jmethodID, ...); jboolean (*CallStaticBooleanMethod)(JNIEnv*, jclass, jmethodID, ...); jbyte (*CallStaticByteMethod)(JNIEnv*, jclass, jmethodID, ...); jchar (*CallStaticCharMethod)(JNIEnv*, jclass, jmethodID, ...); jshort (*CallStaticShortMethod)(JNIEnv*, jclass, jmethodID, ...); jint (*CallStaticIntMethod)(JNIEnv*, jclass, jmethodID, ...); jfloat (*CallStaticFloatMethod)(JNIEnv*, jclass, jmethodID, ...); jdouble (*CallStaticDoubleMethod)(JNIEnv*, jclass, jmethodID, ...); void (*CallStaticVoidMethod)(JNIEnv*, jclass, jmethodID, ...);
如果这里不也不使用CallStaticIntMethod(),而是用CallIntMethod()也是会异常的,如下
JNI DETECTED ERROR IN APPLICATION: calling static method int com.biumall.dynamic.one.Hello.multiply(int, int) with CallIntMethodV
访问域
域也分为静态域和非静态的域。
如果乱使用也是会有异常的,显示使用GetFieldID()去获取static的域出现的异常。
JNI DETECTED ERROR IN APPLICATION: JNI GetStringUTFChars called with pending exception java.lang.NoSuchFieldError: no "Z" field "mBooleanValue" in class "Lcom/biumall/dynamic/one/Hello;" or its superclasses
由于域跟访问方法差不多,这就简单的介绍一下。
public int mIntValue = -0Xff; public static boolean mBooleanValue = true;
非静态
jfieldID intFieldID = env->GetFieldID(clazz, "mIntValue", "I"); if(NULL != intFieldID){ //获取对象域中的值 int intValue = env->GetIntField(object, intFieldID); //修改对象域中的值 env->SetIntField(object, intFieldID, 99); }
静态
jfieldID booleanFieldID = env->GetStaticFieldID(clazz, "mBooleanValue", "Z"); if(NULL != booleanFieldID){ //获取对象域中的值 int booleanValue = env->GetStaticBooleanField(clazz, booleanFieldID); //修改对象域中的值 env->SetStaticBooleanField(clazz, booleanFieldID, false); }
上面只涉及int和boolean类,其他的类型jni.h中也有定义哈。
参考文章
-
《》