JNI中的数据类型以及数据结构 —— 这些结构存在的意义

JNI中的数据类型以及数据结构

一、概述

因为JNI是一套Native层和JVM通信的机制,通信就是信息交流,所以就必须要提供在两种语言间的数据交换的机制。基于这个原因,JNI中通过typedef定义了一套专用的数据类型以及数据结构。

二、Java基本类型

Java TypeNative TypeDescription
booleanjbooleanunsigned 8 bits
bytejbytesigned 8 bits
charjcharunsigned
shortjshortsigned 16 bits
intjintsigned 32 bits
longjlongsigned 64 bits
floatjfloat32 bits
doublejdouble64 bits
voidvoidnot applicable

还添加了一下定义方便使用

  • #define JNI_FALSE 0
  • #define JNI_TRUE 1
  • typedef jint jsize 用于标识索引和大小(C++标准建议用尽量准确的类型符来标识一个变量。比如,表示大小就用size_t等,而不是使用在个平台都有可能产生不一致的int、short等)

三、Java引用类型

JNI 中还包含了一组特殊的类型,用来对应Java中的引用类型,我们暂且称之为JNI引用类型。为了尽量和Java引用类型像照应,JNI引用类型遵照如下层次结构:

  • jobject(用于引用所有Object对象)
    • jclass(用于引用Classs对象)
    • jstring(用于引用String对象)
    • jarray(数组对象)
    • jobjectArray(对象数组)
    • jbooleanArray(boolean数组,不是Boolean数组)
    • jbyteArray(byte数组)
    • jcharArray(char数组)
    • jshortArray(short数组)
    • jintArray(int数组)
    • jlongArray()
    • jfloatArray()
    • jdoubleArray()

JNI在定义这一组JNI引用类型的时候,正对C和C++分别采取了不同的定义方式。C中采用typedef jobject jclass;这种定义。C++因为是面向对象的,所以直接采用了类继承的方式。详见下图

JNI引用类型

可以看到在C中,不管是什么类型本质上都是void* 类型,而C++则是空类并且有了继承关系。可本质上并没有什么区别,使用的时候具体是什么类型仍需要用户自己去区别。

四、Java字段和方法(Field/Method)

Java中的字段和方法定义为C中结构体的指针,如下:

struct _jfieldID;              /* opaque structure */
typedef struct _jfieldID *jfieldID;   /* field IDs */

struct _jmethodID;              /* opaque structure */
typedef struct _jmethodID *jmethodID; /* method IDs */

jfieldID以及jmethodID后面注释了一句 “opaque structure(不透明结构)”,应该是说该结构交给JVM自己去定义。jni.h文件中还定义了JNINativeMethod类型,该类型暂时不用关注,它用于标识一个Java方法(一般在Native方法与Java方法的动态绑定时使用)。

五、JNI Value类型(联合体类型)

typedef union jvalue {
    jboolean z;
    jbyte    b;
    jchar    c;
    jshort   s;
    jint     i;
    jlong    j;
    jfloat   f;
    jdouble  d;
    jobject  l;
} jvalue;

六、JNI中的类型签名

在JNI中个JVM通信时很多时候不使用具体类型(比如boolean、int、class等)而是使用类型签名,并且是直接使用JVM所使用的类型签名(应该是处于效率之类的考虑吧)。JVM中的类型签名如下:

类型签名具体Java类型
Zboolean
Bbyte
Cchar
Sshort
Iint
Jlong
Ffloat
Ddouble
L 接上具体Class的全限定名 ;具体的Class类型
[ 接上类型签名数组类型
(参数签名)方法返回值类型签名方法类型签名

举使用类型签名的一个例子:

一个Java方法:
long f(int n,String s,int[] arr);
其类型签名如下:
(ILjava/lang/String;[I)J

  1. 注意其中的信息:Iint 的类型签名,Ljava/lang/String;String 的类型签名,[Iint[] 的类型签名,J是long的类型签名。* 其合在一起是long f(int n,String s,int[] arr);*这个方法的类型签名。

  2. Java中有方法签名来标识方法的唯一性,那么就有类型签名来标识类型的唯一性(类型签名就是给boolean、int、class等这些找了一个简称或者别称)。

  3. 其中最后一个方法类型签名,在java.lang.invoke包中有一个MethodType类型,该类型属于Java方法签名的一部分,包含方法的参数信息以及返回值信息。我们可以理解为,方法包含类型信息以及方法名信息(类似参数包含参数名以及类型信息)。

七、JNI中UTF-8字符串说明

JNI中使用的字符编码方案是在UTF-8的基础上稍加修改而来的,具体的查看JNI文档(JVM中采用的也是修改过的UTF-8)。

其中涉及到两点不同:

  1. 对空字符(char)0编码时不是像标准UTF-8那样使用一个字节,而是使用两个字节,这就避免了在字符串中嵌入了空值(应该是避免了无意间引入的空字符对JVM的运行产生影响)。
  2. Java VM 无法识别UTF-8的四字节格式,它使用两倍或三倍三字节来代替UTF-8中超过三字节的表示。

八、字符编码说明

因为早前搞OpenVPN的时候仔细去熟悉了下Unicode才算明白Unicode以及UTF-8/UTF-16之间的渊源,简单的提一下。

Unicode(统一码、万国码、单一码),是计算机行业定义的一套字符标准。一般我们提到的时候会说Unicode字符集,讲的是一套字符集,而不是一套编码方案,并且它引入了平面的概念。不讲复杂码位平面什么的,简单点说Unicode字符集用四个字节来指向一个字符,这是字符标准,在你电脑的字体文件中就是通过Unicode的码位来一一照应上文字(不是通过UTF-8或者其他编码方案的值)。而UTF-8/UTF-16等都编码方案,将四个字节的标准Unicode码编码成UTF-8等所定义的编码格式,但是真正用的时候还需要解码回Unicode。之所以这样做,是因为Unicode每个字符都占用4个字节,但常用字符往往没那么多,重新实现编码方案将大大的缩小空间浪费。

九、JNI为什么定义这些信息

JNI是JVM和Native层沟通的桥梁,要达到JVM和Native可以相互沟通的目的,就必须实现下面两点

  1. Java中可以调用Native层的方法(不可避免的需要传递参数),持有Native层数据结构或者对象的引用,保存Native层的变量。
  2. Native同样需要可以调用Java层的方法,持有Java层对象的引用,保存Java层变量。

1、基于方法调用

  1. 在Java层提供了native方法属性,被该属性标记的方法可以和Native层方法产生关联用来代用Native层方法。关联方式有:
    • 静态绑定(通过命名方式绑定)
    • 动态绑定(通过手动写绑定方法绑定,后面会有)
  2. 在Native层呢,就是通过上面的jclass、jmethod等以及方法类型签名来调用。

2、相互保存对方变量以及持有对方引用

  1. Java层持有Native层对象一般很好解决,真毒C/C++来说,直接保存其内存地址或者内存数据即可。
  2. Native层只有Java层对象只能通过jclass、jstring、jobjectArray等来持有对象的引用。数据的保存,比如byte[]等数组类型除了持有引用外还提供一些额外的操作,像copy等,后面会有介绍。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值