JNI函数的实现在c/c++中实现的,如果想访问java中定义的类对象的实例域需要三个步骤:
1.通过GetObjectClass()函数获得该对象的类class,返回值是一个jclass;
2.调用GetFieldID函数得到需要访问的实例域(变量)在该c类中id
3.调用Get【Type】Field()得到访问的变量值。其中【Type】对应变量的类型。
例如:java中有一个int age 对应的【Type】就是Int
GetIntField()
实例1:访问java类中num属性,并对其做加法运算。
java 层:
public class JNIUtils {
public int num = 10;
public native int addNum();
static {
System.loadLibrary("native-lib");
}
}
c++层:
#include <jni.h>
#include <string.h>
#include <stdio.h>
//访问java对象中num属性,并对其作加法运算
extern "C"
jint Java_com_honjane_ndkdemo_JNIUtils_addNum( JNIEnv* env, jobject jobj){
//1.获得实例对应的class类
jclass jcls = env->GetObjectClass(jobj);
//2.通过class类找到对应的field id
//num 为java类中变量名,I 为变量的类型int
jfieldID fid = env->GetFieldID(jcls,"num","I");
//3.通过实例object获得对应的field
jint jnum = env->GetIntField(jobj,fid);
//add
jnum += 10;
return jnum;
}
输出结果:
I/main----addNum: 20
实例2:访问java层static属性,并对其操作
java层:
public static String name = "honjane";
public native void accessStaticField();
定义一个static的变量,然后在c++获取这个变量,对其操作,通过getStaticField返回到java显示。
c++层:
//访问java中静态变量name,并对其赋值
extern "C"
void Java_com_honjane_ndkdemo_JNIUtils_accessStaticField( JNIEnv* env, jobject jobj){
//1.获得实例对应的class类
jclass jcls = env->GetObjectClass(jobj);
//2.通过class类找到对应的静态field id
//name 为java类中变量名,Ljava/lang/String; 为变量的类型String
jfieldID fid = env->GetStaticFieldID(jcls,"name","Ljava/lang/String;");
//3.通过class获得对应的静态field
jstring jstr = (jstring)env->GetStaticObjectField(jcls,fid);
// 将jstring类型转换成字符指针
const char* cstr = env->GetStringUTFChars(jstr, JNI_FALSE);
//定义字符数组
char text[30] = "hello ";
//拼接字符
strcat(text, cstr);
jstring new_str = env->NewStringUTF(text);
// 将jstring类型的变量 , 设置到java
env->SetStaticObjectField(jcls, fid, new_str);
}
输出结果:
I/main----name: hello honjane
这里有几个地方需要注意:
static变量的Field是通过GetStatic【[Type】Field(jcls…),传入的是class,而非static变量获取是通过Get【Type】Field(jobj…)传入的参数是实例object;同理SetStatic【[Type】Field(jcls…)传入的是类class,Set【Type】Field(jobj…)传入的是实例object。
这个也很好理解,静态变量或者方法属于该对象的类class,而非静态变量或方法属于该对象的实例。所以要根据它属于的情况来传参数。
实例3:访问java对象的私有变量
java层
private int age = 21;
public native void accessPrivateField();
public int getAge(){
return age;
}
c++层
//访问java中私有变量age
extern "C"
void Java_com_honjane_ndkdemo_JNIUtils_accessPrivateField( JNIEnv* env, jobject jobj){
jclass jcls = env->GetObjectClass(jobj);
jfieldID jfid = env->GetFieldID(jcls,"age","I");
jint jage = env->GetIntField(jobj, jfid);
jage++;
env->SetIntField(jobj, jfid, jage);
}
输出结果:
I/main----age修改前: 21
I/main----age修改后: 22
我们看到实例3中private变量与实例1中public变量访问在c/c++没有什么区别,访问方式相同。
变量的访问先介绍到这里,下一节介绍jni访问java中方法