JNI 数据类型

Java有基本数据类型和引用数据类型。

基本数据类型

基本数据类型的装换大概就是Java的八大数据类型+void。

Java类型 本地C类型 实际表示的C类型(win32) Signature 说明
boolean jboolean unsigned char Z 无符号,8 位
byte jbyte signed char B 有符号,8 位
char jchar unsigned short C 无符号,16 位
short jshort short S 有符号,16 位
int jint long I 有符号,32 位
long jlong __int64 J 有符号,64 位
float jfloat float F 32 位
double jdouble double D 64 位
void void N/A V N/A

Signature是Java的方法签名。

引用数据类型

Java Native Signature
object jobject L+classname +;
Class jclass Ljava/lang/Class;
String jstring Ljava/lang/String;
Throwable jthrowable Ljava/lang/Throwable;
Object[] jobjectArray [L+classname +;
byte[] jbyteArray [B
char[] jcharArray [C
double[] jdoubleArray [D
float[] jfloatArray [F
int[] jintArray [I
short[] jshortArray [S
long[] jlongArray [J
boolean[] jbooleanArray [Z

由上表我们知道,数组的JNI层数据类型都以”Array”结尾,签名格式最前面都是“[”。有些数据类型的签名以“;”结尾,需要特别的注意。除此之外引用数据类型还存在继承关系,如下图。

由图可知,jclass、jstring、jarray、jthrowable都继承jobject,而jobjectArray、jbyteArray、jcharArray等引用数据类型都继承jarray。具体情况可以自行阅读JNI源码。

方法签名

在上面的表格中,我们除了列举数据类型,同时还列举了相对应的签名格式(Signature),方法签名就是有签名格式所组成的,方法签名在动态代理提到过。

方法签名的格式是:(参数签名格式...)返回值签名格式。比如方法void sayHello(String content);,它的方法签名就是(Ljava/lang/String;)V

想要记住签名格式并写出正确的方法签名其实有些麻烦,好在JDK为我们提供了生成方法签名的工具javap,使用步骤:

  1. 使用javac编译A.javaA.class,例如javac A.java
  2. 使用javap命令,比如javap -s -p A.class。最终结果会在CMD/SHELL窗口显示。
    • 选项s表示内部类型签名。
    • p表示打印出所有的方法和成员(默认打印public成员)。

Java与Native的数据类型装换

java传入的String参数转换为c的char*。

java传入的String参数,在c文件中被jni转换为jstring的数据类型,在c文件中声明char* test,然后test = (char*)(*env)->GetStringUTFChars(env, jstring, NULL);注意:test使用完后,通知虚拟机平台相关代码无需再访问:(*env)->ReleaseStringUTFChars(env, jstring, test);

c中获取的一个char*的buffer传递给java

这个char*如果是一般的字符串的话,作为string传回去就可以了。如果是含有’\0’buffer,最好作为bytearray传出,因为可以制定copylength,如果copystring,可能到’\0’就截断了。

有两种方式传递得到的数据:

  • 一种是在jni中直接new一个byte数组,然后调用函数(*env)->SetByteArrayRegion(env, bytearray, 0, len, buffer);将buffer的值copy到bytearray中,函数直接return bytearray就可以了。
  • 一种是return错误号,数据作为参数传出,但是java的基本数据类型是传值,对象是传递的引用,所以将这个需要传出的byte数组用某个类包一下。