引言
在学习了C语言基础之后 ,我们简单的了解了C语言编程的一些范式 ,了解了指针 ,结构体 ,联合体 ,函数 ,文件IO等等 。我们最终的目的是要学会NDK开发 ,而NDK开发就离不开我们的JNI技术 。下面 ,就来开始我们的JNI之旅吧 。
JNI的概念
JNI全称 Java NativeInterface , java本地化接口 ,可以通过JNI调用系统提供的API ,我们知道 ,不管是linux还是windows亦或是mac os ,这些操作系统 ,都是依靠C/C++写出来的 ,还包括一些汇编语言写的底层硬件驱动 。java和C/C++不同 ,它不会直接编译成平台机器码,而是编译成虚拟机可以运行的java字节码的.class文件,通过JIT技术即时编译成本地机器码,所以有效率就比不上C/C++代码,JNI技术就解决了这一痛点,下面我们来看看JNI调用示意图:
JNI技术.png
从上图可以得知 ,JNI技术通过JVM调用到各个平台的API ,虽然JNI可以调用C/C++ ,但是JNI调用还是比C/C++编写的原生应用还是要慢一点 ,不过对高性能计算来说 ,这点算不得什么 ,享受它的便利 ,也要承担它的弊端 。
JNI开发流程
因为JNI开发并未涉及到NDK ,所有我们的开发工具是eclipse and visual studio 。
第一步:编写java本地方法
publicstaticnativeStringgetStringFromC;
第二步:生成.h头文件 ,需要使用到的java命令是javah
#假定你以配置好java环境 #在控制台中进入工程src目录 >cdE:\java_workspace\Hello_JNI\src>javahcom.zeno.jni.HelloJni#需要注意的是 ,com.zeno.jni.HelloJni,是全类名,包名.类名
第三步:将.h头文件复制到VS的代码文件目录下 ,在解决方案中的头文件目录->右键->添加 ->添加现有项 。将我们的头文件添加进来。
添加头文件.png
添加进来之后 ,打开我们的头文件 ,会发现 ,头文件里面的jni.h这个头文件找不到 ,因为它不是系统的头文件 ,所有我们需要将它找出来 ,并复制到我们的工程项目中 。
#JDK的jni.h头文件目录D:\Java\jdk1.8.0_60\include\jni.h#在jni.h头文件中,又引入了jni_md.h头文件 ,所有这个我们也要一并赋值过来D:\Java\jdk1.8.0_60\include\win32\jni_md.h
将jni.h这个头文件按照上述步骤 ,添加到头文件目录中 ,注意将<>改成" " , <>表示引入的是系统头文件," "表示引入的是第三方头文件。
第四步:实现头文件
//生成的头文件函数/* * Class: com_zeno_jni_HelloJni * Method: getStringFormC * Signature: Ljava/lang/String; */JNIEXPORT jstring JNICALLJava_com_zeno_jni_HelloJni_getStringFromC(JNIEnv *, jclass);
新建一个.c的文件 ,引入我们生成的头文件 ,然后实现我们生成的C语言函数。
/* * Class: com_zeno_jni_HelloJni * Method: getStringFormC * Signature: Ljava/lang/String; */JNIEXPORTjstringJNICALLJava_com_zeno_jni_HelloJni_getStringFromC(JNIEnv*Env,jclassjclazz){return (*Env)->NewStringUTF(Env,"Jni C String");}
第五步:生成动态链接库
补充:
了解了静态库和动态库 ,下面我们就来生成一个动态库,以VS为例:
选中项目 ->右键 ->属性 ->常规 ->项目默认值 ->配置类型 ,选择动态库.dll项目属性配置.png
配置完成之后 ,选中项目 ->生成 。即可生成动态链接库。
动态链接库.png
第六步:配置环境变量
我们生成了.dll文件之后 , java环境并不知道有这个.dll动态链接库的存在 ,所有我们需要将生成.dll的文件目录 ,配置到环境变量中。
配置环境变量.png注意:配置好环境变量 ,需要重新启动eclipse ,不然会找不到动态链接库的。
第七步:加载动态链接库
static{System.loadLibrary("Hello_JNI"); }
第八步 :调用本地方法并执行
/** * *@authorZeno * * JNI (Java NativeInterface) java本地化接口 * * Android Framework层与Native层相互通信的基石 * * */publicclassHelloJni{// java调用C/C++函数的本地方法publicstaticnativeStringgetStringFromC;publicstaticvoidmain(String args){System.out.println("getStringFormC == "+getStringFromC); }static{//加载动态库System.loadLibrary("Hello_JNI"); } }
输出:
getStringFormC == Jni C String
JNI开发的步骤虽然多 ,但大多比较简单 ,操作起来不难 。
结语
这篇是JNI系列的开篇 ,总体来说比较简单 ,先将流程走顺了 ,后续的开发就会好很多 ,流程性的东西 ,需要多操作 ,就会形成固定的套路 。