JNI/NDK入门指南之JNI数据类型,描述符详解

       JNI/NDK入门指南之JNI数据类型,描述符详解


Android JNI/NDK入门指南目录

JNI/NDK入门指南之正确姿势了解JNI和NDK
JNI/NDK入门指南之JavaVM和JNIEnv
JNI/NDK入门指南之JNI数据类型,描述符详解
JNI/NDK入门指南之jobject和jclass
JNI/NDK入门指南之javah和javap的使用和集成
JNI/NDK入门指南之Eclipse集成NDK开发环境并使用
JNI/NDK入门指南之JNI动/静态注册全分析
JNI/NDK入门指南之JNI字符串处理
JNI/NDK入门指南之JNI访问数组
JNI/NDK入门指南之C/C++通过JNI访问Java实例属性和类静态属性
JNI/NDK入门指南之C/C++通过JNI访问Java实例方法和类静态方法
JNI/NDK入门指南之JNI异常处理
JNI/NDK入门指南之JNI多线程回调Java方法
JNI/NDK入门指南之正确姿势了解,使用,管理,缓存JNI引用
JNI/NDK入门指南之调用Java构造方法和父类实例方法
JNI/NDK入门指南之C/C++结构体和Java对象转换方式一
JNI/NDK入门指南之C/C++结构体和Java对象转换方式二



引言

   通过前面的章节正确姿势了解Android中JNI/NDK,我想读者朋友们一定对JNI/NDK的基本概念印象深刻了吗,那么接下来就要开始我们的JNI编程学习了。学编程的东西,一般法则先学习它的最基础数据类型,同理JNI也是如此。既然JNI是用来C/C++和Java通信的,那么JNI为之定义了一系列基本数据类型和引用数据类型用来与Java交织呼应。那么在接下来的篇章里面我们会围绕JNI的数据类型和描述符为中心而开展。

注意:这里都是以32位CPU架构来说明!




基本数据类型

先从最简单的基本数据类型开始,看看JNI语法为其定义的相关法则。

Java Launage TypeJNI Native TypeC/C++ Launage TypeType Description
booleanjbooleanunsigned charunsigned 8 bits
bytejbytesigned charsigned 8 bits
charjcharunsigned shortunsigned 16 bits
shortjshortsigned shortsigned 16 bits
intjintsigned intsigned 32 bits
longjlongsigned longsigned 64 bits
floatjfloatfloat32 bits
doublejdoubledouble64 bits

注意:这些数据类型是可以直接在JNI中直接使用的,不需要进行转换。

	jbyte result=0xff;
	jint size;
	jbyte* timeBytes;


引用数据类型

Java Launage TypeJNI Native TypeType Description
java.lang.Objectjobject可以表示任何Java的对象,或者没有
JNI对应类型的Java对象(实例方法的强制参数)
java.lang.StringjstringJava的String字符串类型的对象
java.lang.ClassjclassJava的Class类型对象(静态方法的强制参数)
Object[]jobjectArrayJava任何对象的数组
boolean[]jbooleanArrayJava boolean型数组
byte[]jbyteArrayJava byte型数组
char[]jcharArrayJava char型数组
short[]jshortArrayJava short型数组
int[]jintArrayJava int型数组
long[]jlongArrayJava long型数组
float[]jfloatArrayJava float型数组
double[]jdoubleArrayJava double型数组
java.lang.ThrowablejthrowableJava的Throwable类型,表示异常的所有类型和子类
voidvoidN/A

注意
(1) JNI中与Java字符串String相对应的jstring也是引用类型,这个切记。
(2) 数组也是引用数据类型,引用类型不能直接使用,要经过JNI函数转换才能使用。参见如下代码:

	//获得一维数组的类引用,即jintArray类型
	jclass intArrayClass = env->FindClass("[I"); 
	int len = 10;
	//构造一个指向jintArray类一维数组的对象数组,该对象数组初始大小为len
	jobjectArray obejctIntArray  =  env->NewObjectArray(len,intArrayClass , NULL);

和Java中的继承关系类似,JNI引用类型也存在一个继承关系,当我们在进行JNI实际开发的时候,可以参照进行相对应的转换:

在这里插入图片描述




类描述符

假设这么一个场景,在JNI的Native方法中,我们要使用Java中的对象怎么办(包括你自定义的或者Android源码中已有的)?即在C/C++中怎么找到Java中的类,这就要使用到JNI开发中的类描述符了。JNI提供的函数中有个FindClass()就是用来查找Java类的,其参数必须放入一个类描述符字符串,类描述符一般是类的完整名称(包名+类名)。这么说是不是很抽象,下面我举几个栗子说明一下:

Java中String类

完整类名:   java.lang.String
对应类描述符: java/lang/String
即一个 Java 类对应的描述符,就是类的全名,其中 . 要换成 / ,最后 不要忘掉末尾的分号。
其实,在实践中,我发现可以直接用该类型的域描述符取代,也是可以成功的。
例如:  jclass intArrCls = env->FindClass(“java/lang/String”)
等同于: jclass intArrCls = env->FindClass(“Ljava/lang/String;”)

Android中Surface类

完整类名:   android.view.Surface
对应类描述符: android/view/Surface
即一个 Android 类对应的描述符,就是类的全名,其中 . 要换成 /

    int err = RegisterMethodsOrDie(env, "android/view/Surface",
            gSurfaceMethods, NELEM(gSurfaceMethods));

    jclass clazz = FindClassOrDie(env, "android/view/Surface");



域描述符

看到这个名词是不是感觉有点懵逼,啥是域描述符。让我为你一一道来,域描述符是JNI中对Java数据类型的一种表示方法(就是对Java类中的变量,在JNI世界的定义),即在JVM虚拟机中,存储数据类型的名称时,是使用指定的描述符来存储,而不是我们习惯的 int,float 等。虽然有类描述符,但是类描述符里并没有说明基本类型和引用数据类型如何表示,所以在JNI中就引入了域描述符的概念。

1 基本类型域描述符

JNI在域描述符中已经定义好了基本类型的表示,其对照表格如下:

Java Launage TypeField Description
intI
longJ
byteB
shortS
charC
doubleD
booleanZ
voidV
其它引用类型L+类全名+;
数组[
方法(参数)返回值

2 引用类型域描述符

一般引用类型则为 L + 该类型类描述符 + ; (注意,这儿的分号“;”只得是JNI的一部分,而不是我们汉语中的分段,下同)。这么说自我感觉也有那么点抽象,让我们举几个栗子说明一下:

2.1 String引用类型域描述符

Java类型:  java.lang.String
JNI 域描述符:Ljava/lang/String;
扩展开来就是 即一个 Java 类对应的描述符,就是 L 加上类的全名,其中 . 要换成 / ,最后 不要忘掉末尾的分号。是不是有点按图索骥的感觉,那么让我么下面接着照葫芦画瓢再接再厉。

2.2 数组引用类型域描述符

对于数组,其通用规则为为 : [ + 其元素类型的域描述符,二维数组就是两个 [ ,以此类推,n维数组就有几个[ + 其元素类型的域描述符。
Java类型:   int[]
JNI域描述符: [I
Java类型:   float[]
JNI域描述符: [F
Java类型:   String[]
JNI域描述符: [Ljava/lang/String;
Java类型:   Object[ ]
JNI域描述符: [[Ljava/lang/Object;
多维数组则是 n个[ +该元素域描述符 , N代表的是几维数组。例如:
Java类型:   int[][]
JNI域描述符: [[I
Java类型:   float[][]
JNI域描述符: [[F

	get_field(env, javaBean_clazz, "boolValue", "Z", &javaBean_t.boolValue);
	get_field(env, javaBean_clazz, "charValue", "C", &javaBean_t.charValue);
	get_field(env, javaBean_clazz, "doubleValue", "D", &javaBean_t.doubleValue);
	get_field(env, javaBean_clazz, "intValue", "I", &javaBean_t.intVaule);
	get_field(env, javaBean_clazz, "array", "[B", &javaBean_t.byteArray);
	get_field(env, javaBean_clazz, "mDoubleDimenArray", "[[I", &javaBean_t.double_dimen_array);
	get_field(env, javaBean_clazz, "stringValue", "Ljava/lang/String;", &javaBean_t.stringValue);
	get_field(env, javaBean_clazz, "mInnerClass", "Lcom/xxx/object2struct/JavaBean$InnerClass;", &javaBean_t.inner_message);



方法描述符

Java世界的类,变量都在JNI世界找到了对应的规则了,各位读者亲朋友们,有没有发现Java类中的方法是不是还没有一个对应的法则呢,本章节就要来说JNI中对应Java方法的方法描述符了。方法描述符定义了方法的返回值和参数的表示形式,将参数类型的域描述符按声明顺序放入一对括号中(如果没有参数则不需要括号),括号后跟返回值类型的域描述符即形成方法描述符。我想各位对方法描述符的定义有了一定理解了,那么让我们来举几个栗子说明一下:

Java MethodMethod Description
String fun()()Ljava/lang/String;
int fun(int i, Object object)(ILjava/lang/Object;)I
void fun(byte[ ] bytes)([B)V
int fun(byte data1, byte data2)(BB)I
void fun()()V

注意,void的处理比较特殊,如果返回值为void,那么方法描述符中必须使用V表示,当void作为参数的时候,忽略。

static JNINativeMethod gMethods[] = {
	{"getJavaBeanFromNative", "()Lcom/xxx/object2struct/JavaBean;",(void*)Java_com_xxx_object2struct_JniTransfer_getJavaBeanFromNative },
	{"transferJavaBeanToNative", "(Lcom/xxx/object2struct/JavaBean;)V",(void*)Java_com_xxx_object2struct_JniTransfer_transferJavaBeanToNative },
};	

补充点:当我们使用JDK内置工具javah生成JNI的头文件的时候(当然这个工具得配置一下才能使用),我们会发现javah头文件注释中已经生成了本地方法的方法描述符,但是它偏不叫方法描述符而是叫做Signature,所以我们也可以把方法描述符直译为签名,形如:

#include <jni.h>
/* Header for class com_xxx_xxxndk_XxxNative */

#ifndef _Included_com_xxx_xxxndk_XxxNative
#define _Included_com_xxx_xxxndk_XxxNative
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_xxx_xxxndk_XxxNative
 * Method:    getCurrentTime
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_xxx_xxxndk_XxxNative_getCurrentTime
  (JNIEnv *, jobject);
/*
 * Class:     com_xxx_apifunctest_test_XxxNative
 * Method:    Prn_Vline
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_com_xxx_apifunctest_test_XxxNative_Prn_1Vline
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif



写在最后

   通过本章的细述,我想各位读者朋友们一定对JNI的数据类型,以及描述符有了比较详细的了解了。在本篇章的最后,我们有说到了javah工具,这个我们会在后面的章节里面详细介绍的。不要着急。青山不改绿水长流,各位江湖见!

  • 14
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值