Java Native Interface(Java本地接口) 简称 JNI,是一种编程框架,使得 JVM 中的 Java程序 可以调用本地应用/或库,也可以被其他程序调用。其过程可以不负责任的理解成 Java 的反射,因为代码逻辑和反射调用很像。
源码
本文所有涉及的所有源码:https://github.com/gavinliu/Study-JNI
平台 | 编译环境 |
---|---|
macOS | gcc |
HelloStringFromC
在java中编写native方法
1 | public class HelloStringFromC { |
生成jni头文件
1 | javac -jni HelloStringFromC |
将会生成 HelloStringFromC.h
1 | /* DO NOT EDIT THIS FILE - it is machine generated */ |
编写native代码
1 |
|
编译so库
1 | gcc HelloStringFromC.c -fPIC -shared -o libhelloString.so |
java调用
1 | public class HelloStringFromC { |
1 | > Hello |
数据类型
基本数据类型
Java 数据类型 | JNI 数据类型 | C 数据类型 |
---|---|---|
blean | jboolean | unsigned char |
byte | jbyte | signed char |
char | jchar | unsigned short |
short | jshort | short |
int | jint | int |
long | jlong | long long |
float | jfloat | float |
double | jdouble | double |
引用类型
Java 数据类型 | JNI 数据类型 |
---|---|
Object | jobject |
Class | jclass |
String | jstring |
array[] | jarray |
数组类型
Java 数据类型 | JNI 数据类型 |
---|---|
boolean[] | jbooleanArray |
byte[] | jbyteArray |
char[] | jcharArray |
short[] | jshortArray |
int[] | jintArray |
long[] | jlongArray |
float[] | jfloatArray |
double | jdoubleArray |
objcet | jobjectArray |
JNIEnv
1 | struct JNINativeInterface_; |
JNIEnv
其实是 JNINativeInterface_
的指针别名,这个结构是C和Java交互的关键类,提供了C数据类型和JNI数据类型的互相转换和C调用Java的相关方法等。
Java 调 C
Java调C的套路:
- 在Java源码中编写native方法
- 使用
javah
生成 jni 头文件 - 实现
jni
方法 - 编译生成 so 动态链接库
- 在Java中使用动态链接库
静态调用
1 | public static native String getFullName(String firstName); |
静态调用生成的JNI方法,第二个参数为 jclass,代表Java中 CallC.class 这个对象。
对象调用
1 | public native String getFirstName(String[] fullName); |
对象调用生成的JNI方法,第二个参数为 jobject,代表Java中 CallC 这个对象。
示例
- Java 调 C 传入一个字符串,返回拼接后的新字符串
- Java 调 C 传入一个字符串数组,返回数组第一个元素
1 |
|
1 | public class CallC { |
1 | > Gavin Liu |
C 调 Java
C调Java的套路:
- 获取 FieldID 或者 MethedID
- 通过 ID 可以 GET|SET Field,和调用 Methed
其中第一步需要用到 Field 和 Methed 签名,可以用 javap
命令获取:
1 | javap -s -p CallJava |
示例
- C 改变 Java 中的成员变量
- C 调用 Java 方法
1 |
|
1 | public class CallJava { |
1 | c.firstName Gavin |
其他
JNIEnv
中还有很多方法,就不作一一介绍,掌握了其套路,代码就很容易写了,比如说调用方法是CallVoidMethod
,调用静态方法就是CallStaticVoidMethod
。
C & C++ 的一些不同
JNIEnv 对象不一样
在C中:JNIEnv*
是一个二级指针,所以是使用 (*env)->
在C++中:JNIEnv*
是一个一级指针,则是使用 env->
引用类型不一样
在C中:是使用结构体实现
在C++中:是使用对象实现
官方文档
http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/jniTOC.html