Java核心技术卷II(第8版) – 读书笔记 – 第12章

本章的内容是JNI(Java Native Interface),即从Java中访问本地方法(其他语言)。

1、当需要在Java中嵌入其他语言编写的代码,如C时,后者称为本地代码。

2、一般来说,Java虽然在单纯运算方面效率慢于C等,但这往往不是性能瓶颈。例如密码运算在某C/S中占用的时间为10%,网络、I/O速度占90%,用C比Java快两倍,则speedup只有1+0.1*2=1.2,只提升了20%(阿姆达尔定律)。

3、当然,如果项目是遗留的,之前已经有了大量,无法被迁移的C++代码时,也只能使用JNI了。

4、Java平台提供了用于和本地C代码进行交互,称为Java本地接口(JNI)。注意:JNI不支持Java类与C++类之间的任何映射!即使你用C++编写代码,也只能使用它的C子集!

5、下面是一个很俗的例子,你已经猜到了。。。Hello JNI。。。

(1) 在Java中先定义好需要JNI的函数,使用关键词native,这里的static是无所谓的,只是这个例子偷懒而已。

(2)然后需要根据上述的.java文件生成.h文件,规则很复杂哦~

(a)函数名规则:包名_类名_函数名
(b)如果有重载,需要加__然后编号
(c) 如果有非UTF-8字符,还需要用xxxx代替。

好吧,不会有人这么自虐的,Java为我们提供了自动生成.h头的方法,两步搞定:

然后就多出这么一个文件:JNITest.h

(3)然后,我们就可以用这个头文件做为函数原型,编写.c了~

(4)编译.so,注意要include两个目录,还要注意生成的so的文件名 lib类名.so

(5)最后在Java代码中,还要加入LoadLibrary:

(6)运行的时候,需要:

或者:

我比较喜欢后面这种方法,恩。

至此,就结束了这个恶俗的例子。。

结果是:

6、由于Java中类型的长度是定的,int就是4字节,long就是8字节,但是C可不是啊亲。。于是,一些映射类型出现了:

jint:4字节,jlong:8字节,jfloat:4字节,jdouble:8字节。
jboolean:1字节,jbyte:1字节,jchar:2字节,jshort:2字节。

7、下面的例子是Java调用C实现加法,主要是演示参数传递。

Java的代码:

.c的代码:

8、JNI中访问字符串略麻烦,下面是一个向Java返回字符串的例子:

上面这个env是函数指针,不是对象哦!

9、如果要反着来,即从C中访问Java的String,需要用GetStringUTFChars或者ReleaseStringUTFChars。

10、虽然C不是OO的,但也可以在JNI代码中访问Java的对象(和之中的实例域),这时就不能用static修饰父了。

11、对象在JNI代码中是jobject类型。

接口封装的比较复杂,步骤是:
(1) GetObjectClass 这只是一个临时引用,旨在方法返回前有效,因此不能直接在class中赋值!它不会返回给Java的。
(2) GetFieldID,这时要指定上面获得的obj、域名、域的数据类型缩写(如Double是D)
(3) GetXXXField() XXX是域类型
(4) SetXXXField()  XXX是域类型

12、如果不想每次执行时都调用一次GetObjectClass,可以用NewGlobalRef锁定对象,但还需要DeleteGlobalRef来释放对象。

13、下面是访问对象的实例域的例子:

Java还算正常,只不过JNI函数头不再是static的了。

C的代码要注意:GetObjectClass获得的cls,只是为了获得FieldID,而SetXXXField和GetXXXField都是在obj上操作的,要分清楚!

再来看一下头问件:

14、访问静态域与上面类似,区别是:
(1)需要用GetStaticFieldID、GetStaticXXXField、SetStaticXXXField等函数。
(2)找class的时候,必须用FindClass,而不是GetObjectClass

15、上面的使用GetFieldID的时候,需要一些代码,例如float是D。

byte  B
char  C
double  D
float  F
int   I
long  J(诡异啊)
short  S
void  V
boolean  Z
数组 [

16、可以使用javap产生函数签名,这实际是写入到了字节码(Java虚拟机来读)的:

17、也可以从本地代码中调用Java中的方法!

18、从JNI代码中调用本地代码的步骤:
(1)GetObjectClass
(2)mid = GetMedhodID
(3)CallXXXMethod(mid) 这里的XXX是函数的返回类型

18、调用静态方法的区别:GetStaticMethodID, CallStaticXXMethod

19、JNI代码中,可以用newObject来构造新的Java对象,并指定方法名为<init>的构造函数。

20、从JNI代码中调用变参数的函数,用CallNonVirtualXXXMethod,带有V的版本是变参数的。

21、JNI代码中可以访问Java的数组,GetArrayLength、GetObjectArray、SetObjectArrayElement。

22、C语言中是没有异常处理的,很可能发生越界等错误,但这些在Java中是会抛出异常的。我们需要在JNI代码中用NewObject来创建Throwable子类的对象。或者调用ExceptionOccured来抛出异常。

23、如果需要清空异常,用ExceptionClear来关闭异常

24、可以在JNI代码中创建虚拟机。JNI_CreateJavaVM。

本章完。

 

 

 

 

 

 

Leave a Reply

Your email address will not be published.