1. 为什么需要native?
2. java层(或者说dalvik)如何识别native函数?
3. java层到native的调用是如何实现的?
4. java和native工作在同一进程吗?
5. native 受dalvik管理吗?
带着这些问题,接下来逐步去分析总结,相信是会有收获的。
一、为什么需要native。
1. 不可反编译。native 编译出来的是目标代码,不可反编译。java编译出来的中间代码可反编译,可反编译可能会导致自己设计思想或者设计算法泄露,很多商业公司是极力避免的。
2. 执行速度快。native 代码一般用c/c++ 实现,执行速度上要比java快些。
3. 方便移植。有些应用在没有android之前,都是用c/c++ 开发的,那么现在要移植到android上,直接移植到native层就不需要另外编写java代码,省时省力。
二、java(或者说dalvik)如何识别native函数
native函数声明会带有native字符,如下例子:
private static native long nativeInit(InputManagerService service,
Context context, MessageQueue messageQueue);
这样编译的时候就把这个native标志位加入到java 函数符号表里,这样就可以和普通的函数区分开了,运行过程虚拟机执行到native函数时就会切换到native执行环境。执行环境是如何切换的呢?还没研究过。
三、java到native的调用是如何实现的
1. 每个虚拟机进程都对应一个JNI环境(JNIEnv)
2. 每个native方法都需要向这个JNI环境测试注册
3. 这些native方法及实现会被编译成一个动态库
4.java层在执行到native代码前需要把这个动态库load进来。之后整个虚拟机进程的JNI环境就包含了native方法入口。
5. java层在执行到native代码时就能通过JNI环境知道native层对应实现。
接下以事件输入系统为例做下分析:
1. native 方法定义数组,格式如下,第一个字段对应的是在java层函数名,第二个是函数形式参数缩写,第三个是native层对应的函数名。
java 层函数形参和native层是有区别的,需要做转换。下面是基本类型转换
缩写 | native 层 | java 层 |
V | void | void |
Z | jboolean | boolean |
I | jint | int |
J | jlong | long |
D | jdouble | double |
F | jfloat | float |
B | jbyte | byte |
C | jchar | char |
S | jshort | short |
[I | jintArray | int[] |
[F | jfloatArray | float[] |
[B | jbyteArray | byte[] |
[C | jcharArray | char[] |
[S | jshortArray | short[] |
[D | jdoubleArray | double[] |
[J | jlongArray | long[] |
[Z | jbooleanArray | Boolean[] |