Java -- JNI中的数据类型
JNI,即Java Native Interface,意为Java本地调用。JNI是一种Java技术,通过使用JNI,我们不仅可以在Java代码里调用C/C++实现的native方法,也可以在native代码里面调用Java实现的方法。从这里大概也可以得出,JNI的出现,一个重要的原因就是“避免重复造轮子“,提高代码复用性。Android framework中,JNI的使用频率非常高;Java层实现业务逻辑、流程控制,再通过JNI调用native方法来完成具体的业务实现。
在Android平台上,JNI就是一座将Native世界和Java世界的天堑变成通途的桥梁。Android平台上JNI所处的位置: Java世界 <--> JNI层 <--> Native世界(引用)。
在JNI中,Java层面的数据类型和引用类型都是不能直接被解析的。即使向JNI传递的是一个简单的int类型,它也不能被直接识别,必须进行相应的类型转换,转换成JNI中与之对应的类型。
下面主要介绍Java和JNI中的类型映射关系。
Java中存在的基本数据类型,在JNI中都有一种特殊的类型与之对应:
| Java类型 | native类型 | 类型描述(C/C++) |
| byte | jbyte | 有符号的8位整型 |
| char | jchar | 无符号的16位整型 |
| short | jshort | 带符号的16位整型 |
| int | jint | 带符号的32位整型 |
| long | jlong | 带符号的64位整型 |
| float | jfloat | 32位浮点型 |
| double | jdouble | 64位浮点型 |
| boolean | jboolean | 无符号的8位整型 |
这些基本数据类型都是可以在native层直接使用的 。不过,务必注意转化成native类型后对应数据类型的字长,例如jchar在native语言中是16位,占两个字节,这和普通的char占一个字节是完全不一样的。其次,Java中void的native类型依旧是void。
类似的,Java中的引用数据类型,在JNI中也有一种特殊的类型与之对应:
| Java类型 | native类型 | 类型描述 |
| java.lang.Object | jobject | 任何Java对象,或者没有对应Java类型的对象 |
| java.lang.String | jstring | 字符串对象 |
| java.lang.Class | jclass | Class对象 |
| java.lang.Throwable | jthrowable | Throwable对象 |
| Object[] | jobjectArray | 任意类型的对象数组 |
| byte[] | jbyteArray | byte类型数组 |
| char[] | jcharArray | char类型数组 |
| short[] | jshortArray | short类型数组 |
| int[] | jintArray | int类型数组 |
| long[] | jlongArray | long类型数组 |
| float[] | jfloatArray | float类型数组 |
| double[] | jdoubleArray | double类型数组 |
| boolean[] | jbooleanArray | 布尔类型数组 |
我们要通过Java层声明的native类型方法,例如:
public native static boolean startDhcp(String interfaceName);
通过JNI调用到native实现(C/C++),必须要有一种联系,将这两类方法连接起来。考虑到Java支持函数重载,JNI选择函数的签名信息(参数列表、返回值)作为连接Java native类型方法和native实现方法的桥梁。有了函数名和它的签名信息,就可以很方便的找到所需的函数了。同样地,在JNI函数签名信息中,也存在对应的类型映射关系:
| Java类型 | 类型签名 |
| boolean | Z |
| byte | B |
| char | C |
| short | S |
| int | I |
| long | J |
| float | F |
| double | D |
| void | V |
| 类 | L + 全限定名,String的类型签名是"Ljava/lang/String;"包括最后的分号 |
| 数组 | [ + 类型签名,byte[]的类型签名是"'[B";"[java/lang/Object;"的Java类型是Object[] |
| 函数声明 | "(参数1,参数2,...)返回值类型" |
请注意,如果Java类型是数组,则标识中会有一个“[”,另外,引用类型(除基本类型的数组外)的标识最后都有一个“;”。
下面从Android源码中,列举一些JNI函数签名的示例:
| Java函数声明 | JNi函数签名 |
| int resetConnections(String interfaceName, int mask) | "(Ljava/lang/String;I)I" |
| boolean startDhcp(String interfaceName) | "(Ljava/lang/String;)Z" |
| boolean getDhcpResults(String interfaceName, DhcpResults dhcpResults) | "(Ljava/lang/String;Landroid/net/DhcpResults;)Z" |
| int bindSocketToNetwork(int socketfd, int netId) | "(II)I" |
| String getDhcpError() | "()Ljava/lang/String;" |
函数的返回值类型出现在函数签名参数列表括号的右侧。
最后JNI中还定义了一个jvalue类型:
typedef union jvalue {
jboolean z;
jbyte b;
jchar c;
jshort s;
jint i;
jlong j;
jfloat f;
jdouble d;
jobject l;
} jvalue;
这个union类型经常作为JNI中参数数组的元素类型:
static void android_animation_PropertyValuesHolder_callMultipleFloatMethod(
JNIEnv* env, jclass pvhObject, jobject target, jlong methodID, jfloatArray arg)
{
jsize parameterCount = env->GetArrayLength(arg);
jfloat *floatValues = env->GetFloatArrayElements(arg, NULL);
jvalue* values = new jvalue[parameterCount];
for (int i = 0; i < parameterCount; i++) {
values[i].f = floatValues[i];
}
env->CallVoidMethodA(target, reinterpret_cast<jmethodID>(methodID), values);
delete[] values;
env->ReleaseFloatArrayElements(arg, floatValues, JNI_ABORT);
}
JNI数据类型映射
本文介绍了Java Native Interface (JNI) 中Java数据类型与native数据类型的映射关系,包括基本数据类型和引用数据类型的转换,以及JNI函数签名示例。
3349

被折叠的 条评论
为什么被折叠?



