7.1 java中的基本类型和引用类型的签名规则
-
jni中 java类的签名为: L + 包名 + 类名,再将原来的
.
改为/
分隔符即可。
例如:java中的java.lang.String
的签名为Ljava/lang/String;
。 -
java中的基本类型的签名为:
Field Descriptor | Java Language Type |
---|---|
Z | boolean |
B | byte |
C | char |
S | short |
I | int |
J | long |
F | float |
D | double |
V | void |
Object | L用/分割的包名 |
- java 中的数组的签名为:左中括号+对象或者基本类型的签名即可;
Field Descriptor | Java Language Type |
---|---|
object[] | [Ljava/lang/Object; |
int[] | [I |
float[] | [F |
7.2 JNI中访问访问java对象的字段并修改
JNI中修改任何java对象的字段值一般分为如下三步:
- 先找到类
- 找到类的字段id
- 通过字段id获取或者更新对象的该字段
如果类实例中还存在别的类的实例 也是按上面的逻辑分析一层层解剖就行
例如:
定义一个叫Person的java类和House的java类:
public class House {
public int size = 100;
public String location = "Beijing";
}
public class Person {
protected String name;
protected int age;
protected House house;
public static int num = 0;
public Person(String name)
{
this.name = name;
this.house = new House();
}
public String getName() {
return name;
}
public void setAge(int age) {
this.age = age;
}
public int getAge() {
return age;
}
public static int getNum() {
return num;
}
}
在默认工程的MainActivity添加两个JNI方法声明第一个为成员访问,第二个静态方法。他们在JNI层的生成的代码是不一样的。在成员实例方法jni方法中的前两个参数 : JNIEnv env, jobject thiz。thiz代表着所在java类的实例。例如本例中是MainActivity
的java实例。取决于这个方法生命在哪个类中。
public native void accessField(Person person);
在static 的 jni方法中的前两个参数 : JNIEnv *env, jclass clazz。clazz代表着所在java类。例如本例中是MainActivity
的java类。取决于这个方法生命在哪个类中。
public static native void accessStaticField(Person person);
接下来在jni中访问Person类的成员变量:
extern "C"
JNIEXPORT void JNICALL
Java_com_memetghini_javaobject_MainActivity_accessField(JNIEnv *env, jobject thiz, jobject person) {
//成员变量
//首先找到类,参数是jni对象
jclass cls = env->GetObjectClass(person);
//再找到成员变量字段id。第一个参数是上面找到的类,第二个参数是字段名,第三个参数为字段签名
jfieldID fid = env->GetFieldID(cls, "name", "Ljava/lang/String;");
//为该成员变量设值,第一个参数为jni对象,第二个参数为要设值的字段id,第三个参数为具体的值
jstring str = env->NewStringUTF("Kadi");
env->SetObjectField(person, fid, str);
//成员对象
//上面已经找到了类,所以先直接找到字段id
jfieldID house_fid = env->GetFieldID(cls, "house", "Lcom/memetghini/javaobject/House;");
//再找jni对象,再从对象中获取字段值或者更改内容,接下来的跟上面相似
jobject house_obj = env->GetObjectField(person, house_fid);
jclass house_cls = env->GetObjectClass(house_obj);
jfieldID size_fid = env->GetFieldID(house_cls, "size", "I");
env->SetIntField(house_obj, size_fid, 1000000);
}
extern "C"
JNIEXPORT void JNICALL
Java_com_memetghini_javaobject_MainActivity_accessStaticField(JNIEnv *env, jclass clazz, jobject person) {
//静态变量的读取也是一样的先通过GetStaticFieldID获取静态变量的字段id
jfieldID num_fid = env->GetStaticFieldID(clazz, "num", "I");
//在用静态变量的字段id获取具体的值。第一个变量为类类型,第二个为静态变量字段id
int num = env->GetStaticIntField(clazz, num_fid);
LOGI("jni num main = %d", num);
//更改静态变量的值。第一个参数为类类型,第二个为静态变量字段id,第三个为具体的值
env->SetStaticIntField(clazz, num_fid, 777);
}
网友评论