Android Java对象和底层结构体转换
来源:互联网 发布:php 判断时间大小 编辑:程序博客网 时间:2024/06/17 23:05
JNI提供了Java和native代码相互调用的接口,注意是相互调用,不仅仅是Java可以调用native,native也是可以调用Java的。但是使用的时候,我们会遇到一些问题,本文介绍一下Java对象和底层结构体的转换。
Java 对象
我们有Person类,
public class Person { public int ID; public String name; public byte[] data;}
底层结构体
Student结构体,由于我们底层采用c实现,而c没有字符串类型(C++有),所以我们采用char数组来存储字符串。
typedef struct { int ID; char name[255]; char data[255];} Student;
我们来介绍,如何将Student对象传递到底层,并将其转换为底层Student结构体。
NDK配置
首先,我们新建一个JNIUtils类,用来从java调用底层代码,
public class JNIUtils { public static native void passJava2Native(Student persion); public static native Student getJavaFromNative(); static { System.loadLibrary("java2struct"); }}
我们定义了两个本地方法,一个是将Java对象传递给底层,另一个是从底层返回一个Java对象。
然后,我们执行javah -jni com.example.java2struct.JNIUtils命令来得到头文件,并得到两个本地方法的函数名,
JNIEXPORT void JNICALL Java_com_example_java2struct_JNIUtils_passJava2Native (JNIEnv *, jclass, jobject);JNIEXPORT jobject JNICALL Java_com_example_java2struct_JNIUtils_getJavaFromNative (JNIEnv *, jclass);
底层接收Java对象
JNIEXPORT void JNICALL Java_com_example_java2struct_JNIUtils_passJava2Native(JNIEnv * env, jclass class, jobject object)
第三个参数就是我们传递进来的Student对象了。问题,就是,我们如何得到其各个成员变量的值呢?
别急,JNI提供了GetFieldID方法,用来得到Java对象的FiledID,调用格式如下(C代码格式,C++代码有所不同),
(*env)->GetFieldID(env, clzz, fieldName, fieldSig);
clzz为jclass类,可以通过(*env)->FindClass来获得,fieldName是成员的名称,fieldSig是成员的签名。关于类型签名,可以参考JNI java 类型签名
得到ID后,我们根据成员的类型来决定调用以下方法,值得注意的是,Java的String也是类,所以可以通过GetObjectField来得到String类型的成员变量。
GetObjectField,
GetBooleanField,
GetByteField,
GetCharField,
GetShortField,
GetIntField,
GetLongField,
GetFloatField,
GetDoubleField,
完整的代码如下,得到所有的成员变量后,我们将其值赋给结构体。
JNIEXPORT void JNICALL Java_com_example_java2struct_JNIUtils_passJava2Native( JNIEnv * env, jclass class, jobject object) { LOGE("call passJava2Native!"); jclass jcRec = (*env)->FindClass(env, "com/example/java2struct/Student"); jfieldID jfID = (*env)->GetFieldID(env, jcRec, "ID", "I"); jfieldID jfname = (*env)->GetFieldID(env, jcRec, "name", "Ljava/lang/String;"); jfieldID jfdata = (*env)->GetFieldID(env, jcRec, "data", "[B"); int ID = (*env)->GetIntField(env, object, jfID); LOGE("ID: %d", ID); jstring name = (jstring)(*env)->GetObjectField(env, object, jfname); //convert jstring to char char* charname = (char*) (*env)->GetStringUTFChars(env, name, 0); LOGD("name: %s", charname); LOGE("name size : %d", strlen(charname)); jbyteArray ja = (jbyteArray)(*env)->GetObjectField(env, object, jfdata); int nArrLen = (*env)->GetArrayLength(env, ja); char *chardata = (char*) (*env)->GetByteArrayElements(env, ja, 0); LOGW("data: %s", chardata); Student student; student.ID = ID; strcpy(student.name, charname); strcpy(student.data, chardata); printStudent(student);}
我们就可以得到相应的成员变量啦。然后我们就可以赋值给结构体。
底层如何返回Java对象
上面介绍了底层如何解析Java对象,这部分介绍底层如何返回一个Java对象,步骤如下,
1. (*env)->FindClass得到类
2. (*env)->AllocObject新建一个类的示例
3. (*env)->GetFieldID得到域ID
4. 设置域,方法如下,
SetObjectField,
SetBooleanField,
SetByteField,
SetCharField,
SetShortField,
SetIntField,
SetLongField,
SetFloatField,
SetDoubleField,
设置域(成员变量)后,然后将该对象返回即可。完整的代码如下,
JNIEXPORT jobject JNICALL Java_com_example_java2struct_JNIUtils_getJavaFromNative( JNIEnv * env, jclass class) { Student student; student.ID = 1234; char *charname = "Paul"; char *chardata = "I am a student"; strcpy(student.name, charname); strcpy(student.data, chardata); printStudent(student); LOGE("call getJavaFromNative!"); jclass jcRec = (*env)->FindClass(env, "com/example/java2struct/Student"); jfieldID jfID = (*env)->GetFieldID(env, jcRec, "ID", "I"); jfieldID jfname = (*env)->GetFieldID(env, jcRec, "name", "Ljava/lang/String;"); jfieldID jfdata = (*env)->GetFieldID(env, jcRec, "data", "[B"); jobject joRec = (*env)->AllocObject(env, jcRec); (*env)->SetIntField(env, joRec, jfID, student.ID); //convert char to jstring jstring jstrn = (*env)->NewStringUTF(env, student.name); (*env)->SetObjectField(env, joRec, jfname, jstrn); //convert char to byte int length = strlen(student.data); jbyteArray jbarr = (*env)->NewByteArray(env, length); jbyte *jb = (*env)->GetByteArrayElements(env, jbarr, 0); memcpy(jb, student.data, length); (*env)->SetByteArrayRegion(env, jbarr, 0, length, jb); (*env)->SetObjectField(env, joRec, jfdata, jbarr); return joRec;}
代码下载地址Github
- Android Java对象和底层结构体转换
- 4、Java 对象底层
- java虚拟机底层结构详解 .
- java虚拟机底层结构详解
- java虚拟机底层结构详解
- java虚拟机底层结构详解
- Android底层JNI中的JavaVM和JNIEnv对象
- Android底层JNI中的JavaVM和JNIEnv对象
- Java对象和XML转换
- Android与Java服务器端数据交互和Java对象转换成JSON对象
- Java类和C结构体之间自动转换
- JSON对象 和 java对象互相转换
- JSON对象和Java对象互相转换
- java对象和json对象互相转换
- 结构体和字节转换
- 结构体和二进制转换
- Android中java层使用LocalSocket和底层进行通讯
- 数据库中树结构数据,转换为Java对象树结构( 多叉树结构 )
- POJ 2488 A Knight's Journey
- 计算机视觉研究 CVonline: The Evolving, Distributed, Non-Proprietary, On-Line Compendium of Computer Vision
- Jquery学习1
- Java EE中Ajax技术简单实现
- IOS 开发 OC(Object_C)与前端页面JS(JavaScript)交互整理(一)
- Android Java对象和底层结构体转换
- ActiveMQ First Demo
- iOS普通字符串和UTF-8之间的相互转换
- 获取iOS app版本信息
- CSDN-markdown编辑器语法简介
- hdu 2586 How far away ?【LCA】
- MMC/SD卡要点
- mfc中 CString转char*
- BZOJ3492: PA2012 Binary Dodgeball