且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

《Android的设计与实现:卷I》——第2章2.4 在Java中调用JNI实现方法

更新时间:2022-09-14 11:50:01

2.4 在Java中调用JNI实现方法

本节介绍如何在Java中调用JNI实现方法、JNI数据类型转换、JNI方法命名规则,以及JNI方法签名规则。

2.4.1 Java数据类型与JNI数据类型转换

Java中调用Native方法传递的参数是Java类型的,这些参数需要经过Dalvik虚拟机转化为JNI类型才能被JNI层识别。下面分基本类型和引用类型介绍这种转化关系。

1.基本类型转化关系

表2-1列出了基本类型的转化关系。


《Android的设计与实现:卷I》——第2章2.4 在Java中调用JNI实现方法
《Android的设计与实现:卷I》——第2章2.4 在Java中调用JNI实现方法

2.引用类型转化关系

JNI的引用类型定义了九种数组类型,以及jobject、jclass、jstring、jthrowable四种类型。要理解其转化关系,首先要理解其继承关系。JNI引用类型的继承关系如图2-3所示。


《Android的设计与实现:卷I》——第2章2.4 在Java中调用JNI实现方法

JNI引用类型采用了与Java类型相似的继承关系。树根是jobject对象,其他所有自定义对象都可以用jobject表示。表2-2中列出了JNI引用类型和Java引用类型的转化关系。


《Android的设计与实现:卷I》——第2章2.4 在Java中调用JNI实现方法

2.4.2 JNI方法命名规则

Log系统中,JNI实现方法与Java声明方法是不同的。例如,Java层声明的Native方法名是isLoggable,而其对应的JNI实现方法的方法名却是android_util_Log_isLoggable。可见,除了数据类型有对应关系外,方法名也有对应关系。

JNI 接口指针是JNI实现方法的第一个参数,其类型是JNIEnv。第二个参数因本地方法是静态还是非静态而有所不同。非静态本地方法的第二个参数是对Java对象的引用,而静态本地方法的第二个参数是对其 Java 类的引用。其余的参数都对应于Java 方法的参数。
JNI规范里提供了JNI实现方法的命名规则,方法名由以下几部分串接而成:

《Android的设计与实现:卷I》——第2章2.4 在Java中调用JNI实现方法

2.4.3 JNI方法签名规则

有了数据类型之间的对应关系,JNI就可以正确识别并转换Java类型。那JNI又是如何识别Java的方法呢?

Java支持方法重载,仅靠函数名是无法唯一确定一个方法的。于是JNI提供了一套签名规则,用一个字符串来唯一确定一个方法。其规则如下:
(参数1类型签名参数2类型签名……参数n类型签名)返回值类型签名
以上签名字符串之间均没有空格。
类型签名又有一些规则,如表2-3所示。

《Android的设计与实现:卷I》——第2章2.4 在Java中调用JNI实现方法
《Android的设计与实现:卷I》——第2章2.4 在Java中调用JNI实现方法

注意 类的签名规则是:“L+全限定类名+;” 三部分组成,其中全限定类名以”/”分隔,而不是用“.”或者“_”分隔。

例如,Java 方法:
long fun (int n, String str, int[] arr);

        其方法签名:

(ILjava/lang/String;[I)J
   括号里面的内容分成三部分,之间没有空格,即“I”、“Ljava/lang/String;”和“[I”,分别代
   表 int、String和int[]。括号外面是返回值类型签名,J代表long型。

回到Log系统的例子,JNINativeMethod结构体中第二个元素便是方法签名信息, 代码如下:
static JNINativeMethod gMethods[] = {
{ "isLoggable", "(Ljava/lang/String;I)Z",(void*)

  android_util_Log_isLoggable },

{ "println_native","(IILjava/lang/String;Ljava/lang/String;)I",(void)

  android_util_Log_println_native },

};

可以看出isLoggable函数有两个参数,一个是String类型,另一个是int类型,返回值为boolean类型。

至此,我们已经可以正确识别类型信息和函数信息。可如何操作对象并访问它们的成员变量和方法呢?下一节继续介绍。