JNI的基本数据类型与C++对java对象的访问
我使用的IDE是Android studio3.3 新建一个项目的时候选择 Native C++会自动创建一个带有Native 方法的项目,返回字符串“Hello From C++”
MainActivity.java
public native String stringFromJNI();
native-lib.cpp
extern "C" JNIEXPORT jstring JNICALL
Java_com_hz_jni02_MainActivity_stringFromJNI(
JNIEnv *env,
jobject /* this */) {
return env->NewStringUTF("Hello from C++");
方法详解:每个native函数(C++),都至少有两个参数(JNIEvn *env ,jclass或者jobject)
1、当native方法(java)方法为静态方法时:jobject代表nactive方法所属类的class对象(MainActivity.class)
2、当native方法(java)方法为非静态方法时:jobject代表native方法所属的对象(MainActivity 对象)。
JNI 的基本数据类型:
java基本数据类型与JNI数据类型对应关系:
//java类型-->JNI类型
boolean-->jboolean
byte-->jbyte
char-->jchar
short-->jshort
int-->jint
long-->jlong
float-->jfloat
double-->jdouble
void-->void
java引用类型(对象)与JNI引用类型(对象)对应关系:
//java引用类型-->JNI引用类型
String -->jstring
Object-->jobject
//数组,基本数据 类型的数据
byte[]-->jByteArray
//对象数组
object[](String[])--> jobjectArray
C++对java对象的访问:
访问修改java类中的属性
1、Java代码:
//声明变量
public String key="jack";
//编写一个native方法返回修改后的变量值
public native String accessField();
//返回修改完事的属性
String str=accessField();
2、C++代码:
extern "C"
JNIEXPORT jstring JNICALL
Java_com_hz_jni02_MainActivity_accessField(JNIEnv *env,
jobject jobj) {
//1、参数jobject jobj是mainActivity对象,并非class
jclass cls=(*env).GetObjectClass(jobj);
//2、jfieldID
//1、jclass 2、属性名称 3、属性签名
jfieldID fid=env->GetFieldID(cls,"key","Ljava/lang/String;");
//3、jack >> super jack 将activity中变量key中的jack变成 super jack
//获取key属性的值
//Get<Type>Field
jstring jstr= static_cast<jstring>(env->GetObjectField(jobj, fid));
printf("jstr:%#x\n",&jstr);
//4、jstring -> c字符串
//isCopy 是否复制(true代表复制,false不复制)
const char* c_str =env->GetStringUTFChars(jstr,JNI_FALSE);
//5、拼接得到新的字符串
char text[20] = "super ";
strcat(text,c_str);
//6、c字符串 ->jstring
jstring new_jstr=env->NewStringUTF(text);
//7修改key
//Set<Type>Field
env->SetObjectField(jobj,fid,new_jstr);
printf("new_jstr:%#x\n", &new_jstr);
return new_jstr;
}
属性签名对照表 就看这个属性的类型是什么样的
访问修改java类中的静态属性
1、Java代码:
//定义一个int类型的静态变量
public static int count=1;
//访问静态属性的方法
public native void accessStaticField();
//调用
Log.d("MainActivity", "访问前count:" + count);
accessStaticField();
Log.d("MainActivity", "访问后count:" + count);
2、C++代码:
extern "C"
JNIEXPORT void JNICALL
Java_com_hz_jni02_MainActivity_accessStaticField(JNIEnv *env, jobject instance) {
//1、获取jClass
jclass cls=(*env).GetObjectClass(instance);
//2、获取jFieldId
jfieldID fld=env->GetStaticFieldID(cls,"count","I");
//3、GetStatic<Type>Field
jint count=env->GetStaticIntField(cls,fld);
count++;
//修改
//SetStatic<Type>Field
env->SetStaticIntField(cls,fld,count);
3、打印结果:
2019-04-24 16:08:42.370 8023-8023/MainActivity: 访问前count:1
2019-04-24 16:08:42.370 8023-8023/MainActivity: 访问后count:2
访问java方法
1、Java代码
//1、定义一个方法
//产生指定范围的随机数
public int genRandomInt(int max){
Log.d("MainActivity", "执行了"+max);
return new Random().nextInt(max);
}
//2、创建一个native方法
public native void accessMethod();
//3、调用native方法
accessMethod();
2、C++代码
extern "C"
JNIEXPORT void JNICALL
Java_com_hz_jni02_MainActivity_accessMethod(JNIEnv *env, jobject instance) {
// 1、获取jclass
jclass cls=(*env).GetObjectClass(instance);
//2、获取jMethodId
// 参数内容1、jclass 2、方法名称 3、方法签名
jmethodID mtd=env->GetMethodID(cls,"genRandomInt","(I)I");
//调用这个方法
//Call<Type>Method
env->CallIntMethod(instance,mtd,200);
}
访问java静态方法
1、Java代码
//1、创建一个方法,产生了一个UUID
public static String getUUID(){
Log.d("MainActivity", "字符串被调用");
return randomUUID().toString();
}
//2、创建一个native方法
public native void accessStaticMethod();
//3、调用native方法
accessStaticMethod();
2、C++代码
// 1、获取jclass
jclass cls=(*env).GetObjectClass(instance);
//2、获取jMethodId
jmethodID mtd=env->GetStaticMethodID(cls,"getUUID","()Ljava/lang/String;");
//3、调用
//Call<Type>Method
env->CallStaticObjectMethod(cls,mtd);
如果要访问构造方法
1、java代码
//1、创建一个准备调用构造方法 的natvie方法
public native void accessConstructor();
//调用native方法
accessConstructor();
2、C++代码
extern "C"
JNIEXPORT void JNICALL
Java_com_hz_jni02_MainActivity_accessConstructor(JNIEnv *env, jobject instance) {
//访问构造方法
//使用java.util.Date产生一个当前的时间戳
jclass cls=(*env).FindClass("java/util/Date");
/*jmethodId*/
jmethodID constructor_mid=env->GetMethodID(cls,"<init>","()V");
//实例化一个Date对象
jobject dateObj=env->NewObject(cls,constructor_mid);
/*调用getTime方法*/
jmethodID mid=env->GetMethodID(cls,"getTime","()J");
jlong time=env->CallLongMethod(dateObj,mid);
printf("\ntime:%lld\n",time);
}
数组的返回:
1、java代码
//定义一个native方法。
public native int[] getArray(int length);
//调用
int[] arrays=getArray(10);
2、C++代码
extern "C"
JNIEXPORT jintArray JNICALL
Java_com_hz_jni02_MainActivity_getArray(JNIEnv *env, jobject instance,jint length) {
//创建一个指定大小的数组
jintArray array=env->NewIntArray(length);
jint* elms=env->GetIntArrayElements(array,NULL);
int i = 0;
for (; i < length; i++){
elms[i] = i;
}
env->ReleaseIntArrayElements(array,elms,0);
return array;
}