我们知道,Java应用程序是一处编码,处处运行的,之所以可以这么威风,靠的就是JVM这个东西,那什么是JVM呢,JVM乃Java虚拟机,是一种虚拟技术,位于java应用程序和特定的操作系统之间,担当着“一处编码,处处运行”的重任。他隐藏了操作系统的差异性,使得运行在上层的java程序可以不用管底层到底是神马操作系统。这样,只要你的机子上有JVM,那么你的机子就可以跑java程序,至于你用的是神马操作系统,我不用管。
可是,有滴时候,我们并不能抛开特定的操作系统的特性,而是用纯粹的java来完成我们的应用。虽然,java是多么多么滴强大,但是他也不是万能的。比如,现在我们的应用需要一些特定操作系统的特性,但是java它不支持,怎么办?或者,我们需要的部分核心功能已经存在了,但是是C/C++的库文件,更常见的一个理由是“这个处理过程性能要求高,java性能忒差,满足不了客户要求,用C/C++吧,性能高”!
如此可见,JNI的存在,总有它的理由。但是JNI的使用,我们破坏了java“一处编码,处处运行”的优势,使得我们的应用是“Host-Dependable”。同时,Java是类型安全的,而C/C++不是滴,所以,使用JNI,java这两大特性就荡然无存了。也因此,要不要使用JNI,我们需要三思而后行。。。
扯了这么远,回过头来,JNI是如何使得Java和C/C++想通的?我们知道,Java之所以不能和C/C++想通,最主要的原因就是类型差异。
关于JNI如何处理类型差异的,后面再说。这里,我们看看Java的数据类型String和C语言的Char*类型是在可见的(黑盒)层面如何相互沟通的。
我们使用Java写个类Jni.java:
JNI为了扮演在c/c++和java之间的匹配工作,它首先需要做的就是既要认识java中的数据类型,也要认识c/c++中的数据类型。这时,jni就相当于一个适配者了。好比,A与C两个人本来不认识,可是现在B认识A,B也认识C,那么通过C的指引和介绍,A和C就认识了!那么jni如何做到既认识C/C++,也认识java呢?其实很简单,一张匹配表足矣,见图!1、原始数据类型的匹配:
其中jni中的本地类型都是以j开头,可以在c/c++中直接和c/C++类型互通互换!2、复杂数据类型的匹配:
简单点的实例来看看java端的类型,如何被C端识别。同时,在C端实现定义的一个类型 如何传递到java端。本篇以String类型为例,看看java端的unicode编码的String类型如何和C端utf-8编码的char*类型进行交互!
2、生成头文件,这里略。。。3、编写C端:讲解在注释中了
可是,有滴时候,我们并不能抛开特定的操作系统的特性,而是用纯粹的java来完成我们的应用。虽然,java是多么多么滴强大,但是他也不是万能的。比如,现在我们的应用需要一些特定操作系统的特性,但是java它不支持,怎么办?或者,我们需要的部分核心功能已经存在了,但是是C/C++的库文件,更常见的一个理由是“这个处理过程性能要求高,java性能忒差,满足不了客户要求,用C/C++吧,性能高”!
如此可见,JNI的存在,总有它的理由。但是JNI的使用,我们破坏了java“一处编码,处处运行”的优势,使得我们的应用是“Host-Dependable”。同时,Java是类型安全的,而C/C++不是滴,所以,使用JNI,java这两大特性就荡然无存了。也因此,要不要使用JNI,我们需要三思而后行。。。
扯了这么远,回过头来,JNI是如何使得Java和C/C++想通的?我们知道,Java之所以不能和C/C++想通,最主要的原因就是类型差异。
关于JNI如何处理类型差异的,后面再说。这里,我们看看Java的数据类型String和C语言的Char*类型是在可见的(黑盒)层面如何相互沟通的。
我们使用Java写个类Jni.java:
package demo.jni; public class Jni { public native int add(); public native String getString(); }在使用javac编译该文件生成Jni.class文件后,我们使用javah -jni来生成一个C语言的头文件(关于javah命令的正确使用,请看我的另一个帖子),该文件名称是demo_jni_Jni.h:
/* DO NOT EDIT THIS FILE - it is machine generated */ #include可以看到,生成的本地方法中,第一个参数类型是JNIEnv*,是一个指向JNIEnv的指针类型,那么JNIEnv是一个什么类型呢? JNIEnv是一个指向了一个Pointer,这个Pointer指向了一张函数表,这张函数表中的每一项就是JNI中的一个函数的入口。本地的方法通过查找这张表来调用某个jni函数,来和JVM交互。如图:/* Header for class demo_jni_Jni */ #ifndef _Included_demo_jni_Jni #define _Included_demo_jni_Jni #ifdef __cplusplus extern "C" { #endif /* * Class: demo_jni_Jni * Method: add * Signature: ()I */ JNIEXPORT jint JNICALL Java_demo_jni_Jni_add (JNIEnv *, jobject); /* * Class: demo_jni_Jni * Method: getString * Signature: ()Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_demo_jni_Jni_getString (JNIEnv *, jobject); #ifdef __cplusplus } #endif #endif
JNI为了扮演在c/c++和java之间的匹配工作,它首先需要做的就是既要认识java中的数据类型,也要认识c/c++中的数据类型。这时,jni就相当于一个适配者了。好比,A与C两个人本来不认识,可是现在B认识A,B也认识C,那么通过C的指引和介绍,A和C就认识了!那么jni如何做到既认识C/C++,也认识java呢?其实很简单,一张匹配表足矣,见图!1、原始数据类型的匹配:
其中jni中的本地类型都是以j开头,可以在c/c++中直接和c/C++类型互通互换!2、复杂数据类型的匹配:
简单点的实例来看看java端的类型,如何被C端识别。同时,在C端实现定义的一个类型 如何传递到java端。本篇以String类型为例,看看java端的unicode编码的String类型如何和C端utf-8编码的char*类型进行交互!
package demo.jni; public class Prompt { //传递给一个String对象 private native String getLine(String str); }
2、生成头文件,这里略。。。3、编写C端:讲解在注释中了
#include可以看到,在生成的本地方法中,原来的String类型的prompt被替换成了jstring。jni提供了GetStringUTFChars方法供我们,将jstring读取到本地。同时提供了NewStringUTF方法,让我们将本地的类型传递到java端。同理,对于其他的类型,比如数组等,操作也是类似,只是所使用的方法不同而已。#include #include "demo_jni_Prompt.h" JNIEXPORT jstring JNICALL Java_demo_jni_Prompt_getLine (JNIEnv *env, jobject clazz, jstring prompt) { /**java中String类型的prompt这里,被转换成了jni中的一个类型jstring。 ***那么这个jstring类型,我们可以直接cout输出吗?答案是否定的。 ***我们知道在java中字符采用的是Unicode编码,在c/c++中,字符使用UTF-8编码 ***我们不需要深入了解Unicode和UTF-8两种编码的具体方法和内容。我们只需要知道 ***Unicode采用的是16-bit编码,而UTF-8采用的是7-bit编码的,所以,我们需要 ***完成这一转换工作,jni已经提供了相应的接口,如下: **/ char buf[128] = "我是从本地代码获取到的"; //字符缓冲 jbyte *str;//jbyte类型对应C中的unsigned char str = (*env)->GetStringUTFChars(env, prompt, NULL); //这个函数就是将jstring类型的字符串转换为本地字符串,返回jbyte*类型 if(str == NULL) { /** GetStringUTFChars方法可能会抛出一个OutOfMemoryError的异常,在jni中的异常机制和java中的并不一样 在java中抛出异常,如果没有捕获,则程序结束运行;但是,在jni中,即使抛出异常,在本地代码的执行顺序依然不变。 所以,这里判断NULL是必须的 **/ return NULL; } printf("%s",str); /** **使用完了utf-8类型的字符后,我们需要释放由上面方法返回的字符串,这样可以释放被这些字符占用的内存空间,避免造成内存瘫痪 **/ (*env)->ReleaseStringUTFChars(env, prompt, str); //下面我们看看如何将本地的代码传到java return (*env)->NewStringUTF(env, buf); //该方法实例化一个UTF-8编码的本地字符串为java.lang.String类型,新创建的就是java中 //Unicode类型的代表同一字符串的实例 //该方法同样可能抛出一个OutOfMemoryError的异常并返回NULL。 }
收藏的用户(0) X
正在加载信息~
推荐阅读
站点信息
- 文章2300
- 用户1336
- 访客10859041
每日一句
Challenges spark life; conquering them gives purpose.
挑战点亮生活,征服赋予意义。
挑战点亮生活,征服赋予意义。
语法错误: 意外的令牌“标识符”
全面理解Gradle - 定义Task
Motrix全能下载工具 (支持 BT / 磁力链 / 百度网盘)
谷歌Pixel正在开始起飞?
获取ElementUI Table排序后的数据
Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call. This is
亲测!虚拟机VirtualBox安装MAC OS 10.12图文教程
华为手机app闪退重启界面清空log日志问题
android ndk开发之asm/page.h: not found
手机屏幕碎了怎么备份操作?
免ROOT实现模拟点击任意位置
新手必看修改DSDT教程
thinkpad t470p装黑苹果系统10.13.2
新会员