// 2. 获取成员变量 id
jfieldID strFieldId = env->GetFieldID(clazz,“testField”,“Ljava/lang/String;”);
// 3. 根据 id 获取值
jstring jstr = static_cast(env->GetObjectField(thiz, strFieldId));
const char* cStr = env->GetStringUTFChars(jstr,NULL);
LOGE(“获取 MainActivity 的 String field :%s”,cStr);
// 4. 修改 String
jstring newValue = env->NewStringUTF(“新的字符创”);
env-> SetObjectField(thiz,strFieldId,newValue);
// 5. 释放资源
env->ReleaseStringUTFChars(jstr,cStr);
env->DeleteLocalRef(newValue);
env->DeleteLocalRef(clazz);
// 获取静态变量
jfieldID staticIntFieldId = env->GetStaticFieldID(clazz,“staticField”,“I”);
jint staticJavaInt = env->GetStaticIntField(clazz,staticIntFieldId);
GetFieldID 和 GetStaticFieldID 需要三个参数:
- jclass
- filed name
- 类型签名: JNI 使用 jvm 的类型签名
类型签名一览表
Type | Signature Java Type |
---|---|
Z | boolean |
B | byte |
C | char |
S | short |
I | int |
J | long |
F | float |
D | double |
V | void |
L fully-qualified-class; | fully-qualified-class |
[type | type[] |
(arg-types) ret-type | method type |
-
基本数据类型的比较好理解,不如要获取一个 int ,GetFieldID 需要传入签名就是 I;
-
如果是一个类,比如 String,签名就是 L+全类名; :Ljava.lang.String;
-
如果是一个 int array,就要写作 [I
-
如果要获取一个方法,那么方法的签名是:(参数签名)返回值签名,参数如果是多个,中间不需要加间隔符,比如: | java 方法|JNI 签名| |–|--| |void f (int n); |(I)V| |void f (String s,int n); |(Ljava/lang/String;I)V| |long f (int n, String s, int[] arr); |(ILjava/lang/String;[I)J|
操作 method
操作 method 和 filed 非常相似,先获取 MethodID,然后对应的 CallXXXMethod 方法
Java层返回值 | 方法族 | 本地返回类型NativeType |
---|---|---|
void | CallVoidMethod() | (无) |
引用类型 | CallObjectMethod( ) | jobect |
boolean | CallBooleanMethod ( ) | jboolean |
byte | CallByteMethod( ) | jbyte |
char | CallCharMethod( ) | jchar |
short | CallShortMethod( ) | jshort |
int | CallIntMethod( ) | jint |
long | CallLongMethod() | jlong |
float | CallFloatMethod() | jfloat |
double | CallDoubleMethod() | jdouble |
在 java 中我们要想获取 MainActivity 的 className 会这样写:
this.getClass().getName()
可以看到需要先调用 getClass 方法获取 Class 对象,然后调用 Class 对象的 getName 方法,我们来看一下如何在 native 方法中调用:
extern “C” JNIEXPORT jstring JNICALL
Java_com_wangzhen_jnitutorial_MainActivity_stringFromJNI(JNIEnv *env, jobject thiz) {
std::string hello = “Hello from C++”;
// 1. 获取 thiz 的 class,也就是 java 中的 Class 信息
jclass thisclazz = env->GetObjectClass(thiz);
// 2. 根据 Class 获取 getClass 方法的 methodID,第三个参数是签名(params)return
jmethodID mid_getClass = env->GetMethodID(thisclazz, “getClass”, “()Ljava/lang/Class;”);
// 3. 执行 getClass 方法,获得 Class 对象
jobject clazz_instance = env->CallObjectMethod(thiz, mid_getClass);
// 4. 获取 Class 实例
jclass clazz = env->GetObjectClass(clazz_instance);
// 5. 根据 class 的 methodID
jmethodID mid_getName = env->GetMethodID(clazz, “getName”, “()Ljava/lang/String;”);
// 6. 调用 getName 方法
jstring name = static_cast(env->CallObjectMethod(clazz_instance, mid_getName));
LOGE(“class name:%s”, env->GetStringUTFChars(name, 0));
// 7. 释放资源
env->DeleteLocalRef(thisclazz);
env->DeleteLocalRef(clazz);
env->DeleteLocalRef(clazz_instance);
env->DeleteLocalRef(name);
return env->NewStringUTF(hello.c_str());
}
创建对象
首先定义一个 java 类:
public class Person {
private int age;
private String name;
public Person(int age, String name){
this.age = age;
this.name = name;
}
public void print(){
Log.e(“Person”,name + age + “岁了”);
}
}
然后我们再 JNI 中创建一个 Person 并调用它的 print 方法:
// 1. 获取 Class
jclass pClazz = env->FindClass(“com/wangzhen/jnitutorial/Person”);
// 2. 获取构造方法,方法名固定为
jmethodID constructID = env->GetMethodID(pClazz,"","(ILjava/lang/String;)V");
if(constructID == NULL){
return;
}
// 3. 创建一个 Pers