Java jvm级别native关键词、JNI详解

1.native关键词的引入

  再完美的编程语言也有自己的不足之处,当然Java也不例外,Java的不足之处除了体现在运行速度(这点往往被一些其他编程语言使用者所诟病)上要比传统的C++慢许多之外,Java无法直接访问到操作系统底层(如系统硬件等),为此Java使用native(原生的)关键词来扩展Java程序的功能。native关键字说明其修饰的方法是一个原生态方法,方法对应的实现不是在当前文件,而是在用其他语言(如C和C++)实现的文件中。Java语言本身不能对操作系统底层进行访问和操作,但是可以通过JNI接口调用其他语言来实现对底层的访问。JNI是Java Native Interface的缩写,它提供了若干的API实现了Java和其他语言的通信(主要C&C++)。从Java1.1开始,JNI标准成为java平台的一部分,它允许Java代码和其他语言写的代码进行交互。JNI一开始是为了本地已编译语言,尤其是C和C++而设计的,但是它并不妨碍你使用其他编程语言,只要调用约定受支持就可以了。使用java与本地已编译的代码交互,通常会丧失平台可移植性。但是,有些情况下这样做是可以接受的,甚至是必须的。例如,使用一些旧的库,与硬件、操作系统进行交互,或者为了提高程序的性能。JNI标准至少要保证本地代码能工作在任何Java 虚拟环境。简而言之,JNI功能即为:Java和本地代码间的双向交互。JNI允许Java代码使用以其他语言编写的代码和代码库。Invocation API(JNI的一部分)可以用来将Java虚拟机(JVM)嵌入到本机应用程序中,从而允许程序员从本机代码内部调用Java代码。

2.JNI的使用场合

1、JAVA程序和本地程序使用TCP/IP或者IPC进行交互。
2、当用JAVA程序连接本地数据库时,使用JDBC提供的API。
3、JAVA程序可以使用分布式对象技术,如JAVA IDL API。
这些方案的共同点是,JAVA和C处于不同的线程,或者不同的机器上。这样,当本地程序崩溃时,不会影响到JAVA程序。
下面这些场合中,同一进程内JNI的使用无法避免:
1、程序当中用到了JAVA API不提供的特殊系统环境才会有的特征。而跨进程操作又不现实。
2、可能想访问一些己有的本地库,但又不想付出跨进程调用时的代价,如效率,内存,数据传递方面。
3、JAVA程序当中的一部分代码对效率要求非常高,如算法计算,图形渲染等。
总之,只有当必须在同一进程中调用本地代码时,再使用JNI。

3.JNI的书写步骤

第一步:编写带有native声明的方法的Java类

第二步:使用javac命令编译编写的Java类

第三步:使用java -jni 来生成后缀名为.h的头文件

第四步:使用其他语言(C、C++)实现本地方法

第五步:将本地方法编写的文件生成动态链接库

第六步:运行程序

4.一个JNI的简单应用例子(以HelloJNI为例子)

第一步:编写带有native声明的方法的Java类

public class HelloJNI {
    public native void displayHelloJNI();//所有native关键词修饰的都是对本地的声明
    static {
        System.loadLibrary("hello");//载入本地库
    }
    public static void main(String[] args) {
        new JNI().displayHelloJNI();
    }
}

声明native方法:如果想将一个方法做为一个本地方法的话,那么就必须声明该方法为native,并且不能实现。 Load动态库:System.loadLibrary("hello");加载动态库(可以这样理解:方法 displayHelloJNI()没有实现,但是在后续步骤中就直接使用了,所以必须在使用之前对它进行初始化),这里一般是以static块进行加载的。同时需要注意的是System.loadLibrary()的参数“hello”是动态库的名字。

第二步:使用javac命令编译编写的Java类

javac HelloJNI.java

注意:JDK环境变量的配置

第三步:使用java -jni 来生成后缀名为.h的头文件( 生成扩展名为h的头文件javah HelloJNI)

头文件javah HelloJNI内容如下:

 1 /*DO NOT EDI TTHIS FILE - it is mach inegenerated*/
 2 #include<jni.h>
 3 /*Header for class HelloJNI*/
 4  
 5 #ifndef_Included_HelloJNI
 6 #define_Included_HelloJNI
 7 #ifdef__cplusplus
 8 extern"C"{
 9 #endif
10 /*
11 *Class:HelloJNI
12 *Method:displayHelloJNI
13 *Signature:()V
14 */
15 JNIEXPORTvoidJNICALL
16 Java_HelloJNI_displayHelloJNI(JNIEnv*,jobject);
17  
18 #ifdef__cplusplus
19 }
20 #endif
21 #endif

注意:这个h文件相当于在java里面的接口,这里声明了一个Java_HelloJNI_displayHelloJNI (JNIEnv *, jobject)方法,然后在本地方法里面实现这个方法,也就是说在编写C/C++程序的时候所使用的方法名必须和这里的一致

第四步:使用其他语言(C、C++)实现本地方法(编写本地方法实现和由javah命令生成的头文件里面声明的方法名相同的方法)

 1 #include"jni.h"
 2 #include"HelloJNI.h"
 3  
 4 //#includeotherheaders
 5  
 6 JNIEXPORT void JNICALL
 7 Java_HelloJNI_displayHelloJNI(JNIEnv*env,jobject obj)
 8 {
 9 printf("HelloJNI!\n");
10 return;
11 }

注意:代码第一行需要将jni.h(该文件可以在%JAVA_HOME%/include文件夹下面找到)文件引入,因为在程序中的JNIEnv、 jobject等类型都是在该头文件中定义的;另外在第2行需要将HelloJNI.h头文件引入,然后保存为 HelloJNIImpl.c。

第五步:将本地方法编写的文件生成动态链接库

这里以在Windows中为例,需要生成dll文件。在保存HelloWorldJNI.c文件夹下面,使用VC的编辑器cl为:cl -I%java_home%\include -I%java_home%\include\win32 -LD HelloJNIImp.c -Fehello.dll 注意:生成的dll文件名在选项-Fe后面配置,这里是hello,因为在HelloJNI.java文件中我们loadLibary的时候使用的名字是hello。当然这里修改之后那里也需要修改。另外需要将-I%java_home%\include -I%java_home%\include\win32参数加上,因为在第四步里面编写本地方法的时候引入了jni.h文件。
如果配置了MinGW,也可以这样来编译:gcc -Wall -D_JNI_IMPLEMENTATION_ -Wl,--kill-at -Id:/java/include –Id:/java/include/win32 -shared -o (输出的dll文件名,如sum.dll) (输入的c/c++源文件,如abc.c)。
第六步:运行程序
运行javaHelloJNI;如果用eclipse/myeclipse,需将dll或so文件放在项目下,而不是src及其子目录下;如果用命令行编译,把dll文件放在该包的同目录下。

 

 

 
 

 

转载于:https://www.cnblogs.com/canvas512732559/p/7027370.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值