Android NDK基础11:JNI数据类型_C调用Java
JNI数据类型
jclass和jobject
//每个native函数,都至少有两个参数(JNIEnv*, jclass或者jobject)
//1)当native方法为静态方法时:
//jclass 代表native方法所属类的class对象(JniTest.class)
//2)当native方法为非静态方法时:
//jobject 代表native方法所属的对象
基本数据类型
Java基本数据类型与JNI数据类型的映射关系
Java Type | Native Type | Description |
---|---|---|
boolean | jboolean | unsigned 8 bits |
byte | jbyte | signed 8 bits |
char | jchar | unsigned 16 bits |
short | jshort | signed 16 bits |
int | jint | signed 32 bits |
long | jlong | signed 64 bits |
float | jfloat | 32 bits |
double | jdouble | 64 bits |
void | void | N/A |
引用类型(对象)
//String jstring
//Object jobject
//Class jobject
//数组,基本数据类型的数组
//boolean[] jbooleanArray
//byte[] jbyteArray
//char[] jcharArray
//short[] jshortArray
//int[] jintArray
//long[] jlongArray
//float[] jfloatArray
//double[] jdoubleArray
//对象数组
//String[] jobjectArray
//object[] jobjectArray
C/C++访问Java的成员
类型签名
Type Signature | Java Type |
---|---|
Z | boolean |
B | byte |
C | char |
S | short |
I | int |
J | long |
F | float |
D | double |
Ljava/lang/String | String |
L{fully-qualified-class}; | fully-qualified-class |
[{type} | type[] |
访问属性
#define _CRT_SECURE_NO_WARNINGS
#include "cn_appblog_jni_JniTest.h"
#include <string.h>
//修改属性key
JNIEXPORT jstring JNICALL Java_cn_appblog_jni_JniTest_accessField
(JNIEnv *env, jobject jobj) {
//jobj是t对象,JniTest.class
jclass cls = (*env)->GetObjectClass(env, jobj);
//jfieldID
//属性名称,属性签名
jfieldID fid = (*env)->GetFieldID(env, cls, "key", "Ljava/lang/String;");
//jason >> super jason
//获取key属性的值
//Get<Type>Field
jstring jstr = (*env)->GetObjectField(env, jobj, fid);
printf("jstr:%#x\n", &jstr);
//jstring -> c字符串
//第三个参数isCopy 是否复制(true代表复制,false不复制)
char *c_str = (*env)->GetStringUTFChars(env, jstr, JNI_FALSE);
//拼接得到新的字符串
char text[20] = "super ";
strcat(text, c_str);
//c字符串 ->jstring
jstring new_jstr = (*env)->NewStringUTF(env, text);
//修改key
//Set<Type>Field
(*env)->SetObjectField(env, jobj, fid, new_jstr);
printf("new_jstr:%#x\n", &new_jstr);
return new_jstr;
}
访问静态属性
JNIEXPORT void JNICALL Java_cn_appblog_jni_JniTest_accessStaticField
(JNIEnv *env, jobject jobj) {
//jclass
jclass cls = (*env)->GetObjectClass(env, jobj);
//jfieldID
jfieldID fid = (*env)->GetStaticFieldID(env, cls, "count", "I");
//GetStatic<Type>Field
jint count = (*env)->GetStaticIntField(env, cls, fid);
count++;
//修改
//SetStatic<Type>Field
(*env)->SetStaticIntField(env, cls, fid, count);
}
访问对象方法
//获取指定类所有属性和方法的签名
> javap -s -p cn.appblog.jni.JniTest
JNIEXPORT void JNICALL Java_cn_appblog_jni_JniTest_accessMethod
(JNIEnv *env, jobject jobj) {
//jclass
jclass cls = (*env)->GetObjectClass(env, jobj);
//jmethodID
jmethodID mid = (*env)->GetMethodID(env, cls, "genRandomInt", "(I)I");
//调用
//Call<Type>Method
jint random = (*env)->CallIntMethod(env, jobj, mid, 200);
printf("random num:%ld", random);
//.....
}
访问静态方法
JNIEXPORT void JNICALL Java_cn_appblog_jni_JniTest_accessStaticMethod
(JNIEnv *env, jobject jobj) {
//jclass
jclass cls = (*env)->GetObjectClass(env, jobj);
//jmethodID
jmethodID mid = (*env)->GetStaticMethodID(env, cls, "getUUID", "()Ljava/lang/String;");
//调用
//CallStatic<Type>Method
jstring uuid = (*env)->CallStaticObjectMethod(env, cls, mid);
//随机文件名称 uuid.txt
//jstring -> char*
//isCopy JNI_FALSE,代表java和c操作的是同一个字符串
char *uuid_str = (*env)->GetStringUTFChars(env, uuid, JNI_FALSE);
//拼接
char filename[100];
sprintf(filename, "D://%s.txt", uuid_str);
FILE *fp = fopen(filename,"w");
fputs("I love Joe", fp);
close(fp);
}
访问构造方法
//使用java.util.Date产生一个当前的时间戳
JNIEXPORT jobject JNICALL Java_cn_appblog_jni_JniTest_accessConstructor
(JNIEnv *env, jobject jobj) {
jclass cls = (*env)->FindClass(env, "java/util/Date");
//jmethodID
jmethodID constructor_mid = (*env)->GetMethodID(env, cls, "<init>", "()V");
//实例化一个Date对象
jobject date_obj = (*env)->NewObject(env, cls, constructor_mid);
//调用getTime方法
jmethodID mid = (*env)->GetMethodID(env, cls, "getTime", "()J");
jlong time = (*env)->CallLongMethod(env, date_obj, mid);
printf("\ntime:%lld\n", time);
return date_obj;
}
Java层调用
public class JniTest {
public String key = "joe";
public static int count = 9;
//访问属性,返回修改之后的属性内容
public native String accessField();
public native void accessStaticField();
public native void accessMethod();
public native void accessStaticMethod();
public native Date assessConstructor();
public static void main(String[] args) {
JniTest t = new JniTest();
System.out.println("key修改前:" + t.key);
t.accessField();
System.out.println("key修改后:" + t.key);
System.out.println("count修改前:" + count);
t.accessStaticField();
System.out.println("count修改后:" + count);
t.accessMethod();
t.accessStaticMethod();
t.assessConstructor();
}
//产生指定范围的随机数
public int genRandomInt(int max) {
System.out.println("genRandomInt 执行了...");
return new Random().nextInt(max);
}
//产生UUID字符串
public static String getUUID() {
return UUID.randomUUID().toString();
}
//加载动态库
static {
System.loadLibrary("JniTest");
}
}
调用父类的方法
public class Human {
@Override
public void sayHi() {
System.out.println("父类:sayHi");
}
}
public class Man extends Human {
@Override
public void sayHi() {
super.sayHi();
System.out.println("子类:sayHi");
}
}
public class JniTest {
public Human human = new Man();
public native Date assessNonvirtualMethod();
public static void main(String[] args) {
JniTest t = new JniTest();
t.assessNonvirtualMethod();
}
//加载动态库
static {
System.loadLibrary("JniTest");
}
}
JNIEXPORT void JNICALL Java_cn_appblog_jni_JniTest_accessNonvirtualMethod
(JNIEnv *env, jobject jobj) {
jclass cls = (*env)->GetObjectClass(env, jobj);
//获取man属性(对象)
jfieldID fid = (*env)->GetFieldID(env, cls, "human", "Lcc/androidios/jni/Human;");
//获取
jobject human_obj = (*env)->GetObjectField(env, jobj, fid);
//执行sayHi方法
jclass human_cls = (*env)->FindClass(env, "cc/androidios/jni/Human"); //注意:传父类的名称
jmethodID mid = (*env)->GetMethodID(env, human_cls, "sayHi", "()V");
//执行
//(*env)->CallObjectMethod(env, human_obj, mid);
//调用的父类的方法
(*env)->CallNonvirtualObjectMethod(env, human_obj, human_cls, mid);
}
中文问题
public class JniTest {
public native String chineseChars(String content);
public static void main(String[] args) {
JniTest t = new JniTest();
t.chineseChars("中文");
}
//加载动态库
static {
System.loadLibrary("JniTest");
}
}
JNIEXPORT jstring JNICALL Java_cn_appblog_jni_JniTest_chineseChars
(JNIEnv *env, jobject jobj, jstring content) {
//输出
//char *c_str = (*env)->GetStringUTFChars(env, content, JNI_FALSE);
//printf("%s\n", c_str);
//c -> jstring
char *c_str = "马蓉与宋江";
//char c_str[] = "马蓉与宋喆";
//jstring jstr = (*env)->NewStringUTF(env, c_str);
//执行String(byte bytes[], String charsetName)构造方法需要的条件
//1.jmethodID
//2.byte数组
//3.字符编码jstring
jclass str_cls = (*env)->FindClass(env, "java/lang/String");
jmethodID constructor_mid = (*env)->GetMethodID(env, str_cls, "<init>", "([BLjava/lang/String;)V");
//jbyte -> char
//jbyteArray -> char[]
jbyteArray bytes = (*env)->NewByteArray(env, strlen(c_str));
//byte数组赋值
//0->strlen(c_str),从头到尾
//对等于,从c_str这个字符数组,复制到bytes这个字符数组
(*env)->SetByteArrayRegion(env, bytes, 0, strlen(c_str), c_str);
//字符编码jstring
jstring charsetName = (*env)->NewStringUTF(env, "GB2312");
//调用构造函数,返回编码之后的jstring
return (*env)->NewObject(env, str_cls, constructor_mid, bytes, charsetName);
}
版权声明:
作者:Joe.Ye
链接:https://www.appblog.cn/index.php/2023/02/25/android-ndk-basic-jni-data-type-c-calls-java/
来源:APP全栈技术分享
文章版权归作者所有,未经允许请勿转载。
THE END
0
二维码
打赏
海报
Android NDK基础11:JNI数据类型_C调用Java
JNI数据类型
jclass和jobject
//每个native函数,都至少有两个参数(JNIEnv*, jclass或者jobject)
//1)当native方法为静态方法时:
//jclass 代表native方法……
文章目录
关闭
共有 0 条评论