1 真实的情景和互动的对象
都有哪些Java和C交互的场景?真实的场景是:
1、一个C程序被系统加载并运行(比如java.exe)
2、C程序加载Java虚拟机并运行一个Java类(这个动作使用Invocation API接口)
3、有可能,这个运行的Java类需要加载一个C库(通过System.loadLibrary函数),C库代码和这个Java类互动,包括互相调用函数和访问变量(这个是通常所言的JNI,通过env指向的函数列表来实现相互操作)
其中第二个场景有互动需求,注意依赖关系是C加载Java。其中第三个场景有互动需求,注意依赖关系是Java加载C。
哪些可以互动?必须是某种实体。
C侧:
变量
函数
Java侧:
对象
对象的公有方法和变量
类的静态方法和静态变量
上述个体都可能成为互动的对象,只有方法或函数可以成为互动的发起者
至此我们理清楚了互动情景。下面我们来梳理互动的操作细节
2 第三个场景,Java代码加载C代码
根据场景来区分。先研究第三个场景,也即Java代码加载C代码。
2.1 可能的互动
Java代码加载C代码时可能出现的互动:
Java访问C侧
看到的范例是Java调用C函数
Java可以访问C变量吗?未知,细节留待以后研究
C可以有全局或静态变量吗?可以
C可以重入吗?未知,取决于C侧代码设计
C访问Java侧
C可以通过JNI接口查找和访问Java侧类
C可以通过JNI接口调用Java侧类构造方法,用以生成对象
C可以通过JNI接口访问Java侧对象的变量和方法
C可以通过JNI接口访问Java侧类的静态变量和静态方法
2.2 Java访问C侧
Java侧访问C侧函数的找寻方法:
1、通过函数原型匹配,注意函数原型是通过函数名和其他信息一起组合生成的
2、通过注册函数直接强制链接。注意C库中的JNI_OnLoad()会被自动和首先调用,可以在其中注册和链接
函数原型样式:
JNIEXPORT void JNICALL Java_HelloJNI_printHello(JNIEnv *, jobject, jstring)
JNIEnv指向JNI接口的功能函数表,表中各种函数往往用来转换数据,或者访问其他
如果是C++,可以省略掉这个参数
jobject指向调用的发出者,说明这里是对象发出对C的调用。如果是类的静态方法在调用C代码的话,这里是jclass。
jstring是一个参数示例
2.3 C访问Java侧
实质是,plain的C代码怎样访问用对象封装的Java元素
怎样访问一个Java类的变量和方法?首先是这些资源被编码了,并生成了签名,可以根据签名去索引。
可能的访问
C可以访问JNI接口函数,当然JNI接口函数也就是为C准备的
C可以通过JNI接口函数查找和访问Java侧类
C可以通过JNI接口函数调用Java侧类构造方法,用以生成对象
C可以通过JNI接口函数访问Java侧对象的变量和方法
C可以通过JNI接口函数访问Java侧类的静态变量和静态方法
有哪些因素在访问中需要考虑?
1、双方有不同的基本数据类型,包括各种char、int、long等等,需要使用一个统一的本地类型:jchar、jint、jlong
2、Java有类和对象的概念,还有String,但C只有plain string,因此C侧需要从Java对象中抽取数据,或组合plain数据为Java对象
以上转换都通过调用JNI接口函数来实现,也即函数原型中“JNIEnv * env”参数所指向的函数列表
3 第二个场景,C代码加载Java代码
在C程序中运行Java类,即Invocation API
在C程序中运行Java类,即Invocation API
两个用途实例:
1、java.exe由C语言编写,通过Invocation API执行Java类
2、Android系统Launcher加载dalvikvm
加载过程一共7步
1.生成java虚拟机选项
2.生成java虚拟机
res = JNI_CreateJavaVM(&vm, (void **)&env, &vm_args);
3.查找并加载类
cls = (*env)->FindClass(env, "InvocationApiTest");
4.获取main()方法的ID
mid = (*env)->GetStaticMethodID(env, cls, "main", "([Ljava/lang/String;)V");
5.生成字符串对象,用作main()方法的参数
6.调用main()方法
(*env)->CallStaticVoidMethod(env, cls, mid, args);
7.销毁Java虚拟机
(*vm)->DestroyJavaVM(vm);
4 一些JNI接口细节
值得关注的有:
1、JNI函数列表里面都有什么?
大体如下三类:
类、对象、变量、方法等的引用及操作
字符串、数组操作
虚拟机接口、异常、C和Java之间函数关联
2、怎样查看方法和变量等的签名?
可以使用javap.exe进行签名。不过看几个范例几乎也能猜出来。
3、局部和全局引用
C侧可以获取Java侧实体的引用,缺省是局部应用,函数退出后即失效。一直有效的话可以使用全局引用。
显然,引用不是一个简单的指向实体的指针,不然怎么会失效呢?
5 参考文档
1、The Java Native Interface Programmer's Guide and Specification
2、Java Native Interface Specification
3、《Android框架揭秘》[韩]金泰延
前面两篇是官方的专业文档,有所有细节,但是看起来头疼且太耗时间,没有必要。《Android框架揭秘》一书对JNI做了很细致很易懂的而且足够的介绍。此书各部分都写得非常仔细,甚至略有啰嗦,各处都有自己的的整理或见解,可以看出作者写书非常的认真尽责,不是拷贝粘贴,所以在此我要大力推荐这本书。