- 你的Java代码,需要得到一个文件的属性。但是你找遍了JDK帮助文档也找不到相关的API。
- 在本地还有一个别的系统,不过他不是Java语言实现的,这个时候你的老板要求你把两套系统整合到一起。
- 你的Java代码中需要用到某种算法,不过算法是用C实现并封装在动态链接库文件(DLL)当中的。
对于上述的三种情况,如果没有JNI的话,那就会变得异常棘手了。
步骤1.新建用eclipse创建一个Java工程,新建一个SyaHelloToCPP,如下
步骤2.在终端进入工程的根目录,输入命令:
javah -classpath /Users/guiqulai/Documents/cocos3.0_project/TESTP/bin -d bin/class -jnicom.fyb.jnitest.SayHelloToCpp
命令解释:javah是帮助生成地层c/c++头文件的命令。 -classpath指定编译好的java字节码(.class)文件位置.但不包含包对应的路径。注意这里最后是进入"bin"文件夹。如果classpath不正确,会出现"找不到类 ..."的错误
-d指定生成的头文件保存的位置 -jni 指定完整的包名+类名
注意:在执行javah的时候,要输入完整的包名+类名。否则在以后的测试调用过程中会发生java.lang.UnsatisfiedLinkError这个异常
步骤3.接下来编写 Android.mk,该文件可以直接从NDK的samples下的hello-jni的jni文件下直接靠过来改改就可以了。
其中只需要该LOCAL_MODULE和LOCAL_SRC_FILES就可以了。
说明:LOCAL_MODULE是描述模块的,用来给java调用的模块名,会生成对应的libSayHelloToCpp.so
LOCAL_SRC_FILES就是源文件,多个文件空格隔开即可。
工程目录下存在一个jni文件夹,把c/c++类文件和android.mk移到jni目录下
打开命令窗口,进入到项目底下,输入$NDK_ROOT/ndk-build命令,即可自动生成libs/armeabi/libtestJni.so文件。
如果报错,指定NDK_PROJECT_PATH,如下面命令。
$NDK_ROOT/ndk-build NDK_PROJECT_PATH=/Users/guiqulai/Documents/cocos3.0_project/TESTP
应该会提示.so文件生成成功
其实在Java代码中,除了对本地方法标注native关键字和加上要加载动态链接库之外,JNI基本上是对上层coder透明的,上层coder调用那些本地方法的时候并不知道这个方法的方法体究竟是在哪里,这个道理就像我们用JDK所提供的API一样。所以在Java中使用JNI还是很简单的,相比之下在C++中调用java,就比前者要复杂的多了。
现在来介绍下JNI里的数据类型。在C++里,编译器会很据所处的平台来为一些基本的数据类型来分配长度,因此也就造成了平台不一致性,而这个问题在Java中则不存在,因为有JVM的缘故,所以Java中的基本数据类型在所有平台下得到的都是相同的长度,比如int的宽度永远都是32位。基于这方面的原因,java和c++的基本数据类型就需要实现一些mapping,保持一致性。下面的表可以概括:
Java类型 | 本地类型 | JNI中定义的别名 |
int | long | jint |
long | _int64 | jlong |
byte | signed char | jbyte |
boolean | unsigned char | jboolean |
char | unsigned short | jchar |
short | short | jshort |
float | float | jfloat |
double | double | jdouble |
Object | _jobject* | jobject |
上面的表格是我在网上搜的,放上来给大家对比一下。对于每一种映射的数据类型,JNI的设计者其实已经帮我们取好了相应的别名以方便记忆。如果想了解一些更加细致的信息,可以去看一些jni.h这个头文件,各种数据类型的定义以及别名就被定义在这个文件中。