1、认识 native 即 JNI,Java Native Interfacejava
凡是一种语言,都但愿是纯。好比解决某一个方案都喜欢就单单这个语言来写便可。Java平台有个用户和本地C代码进行互操做的API,称为Java Native Interface (Java本地接口)。c++
2、用 Java 调用 C 的“Hello,JNI”程序员
咱们须要按照下班方便的步骤进行:编程
一、建立一个Java类,里面包含着一个 native 的方法和加载库的方法 loadLibrary。HelloNative.java 代码以下:安全
public class HelloNative { static { System.loadLibrary("HelloNative"); } public static native void sayHello(); @SuppressWarnings("static-access") public static void main(String[] args) { new HelloNative().sayHello(); } }
首先让你们注意的是native方法,那个加载库的到后面也起做用。native 关键字告诉编译器(实际上是JVM)调用的是该方法在外部定义,这里指的是C。若是你们直接运行这个代码, JVM会告之:“A Java Exception has occurred.”控制台输出以下:多线程
Exception in thread "main" java.lang.UnsatisfiedLinkError: no HelloNative in java.library.path at java.lang.ClassLoader.loadLibrary(Unknown Source) at java.lang.Runtime.loadLibrary0(Unknown Source) at java.lang.System.loadLibrary(Unknown Source) at HelloNative.<clinit>(HelloNative.java:5)
这是程序使用它的时候,虚拟机说不知道如何找到sayHello。下面既能够手动写,天然泥瓦匠是用并发
二、运行javah,获得包含该方法的C声明头文件.happ
将HelloNative.java ,简单地 javac javah,如图jvm
就获得了下面的 HelloNative.h文件 :编程语言
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class HelloNative */ #ifndef _Included_HelloNative #define _Included_HelloNative #ifdef __cplusplus extern "C" { #endif /* * Class: HelloNative * Method: sayHello * Signature: ()V */ JNIEXPORT void JNICALL Java_HelloNative_sayHello (JNIEnv *, jclass); #ifdef __cplusplus } #endif #endif
jni.h 这个文件,在/%JAVA_HOME%include
三、根据头文件,写C实现本地方法。
这里咱们简单地实现这个sayHello方法以下:
#include "HelloNative.h" #include <stdio.h> JNIEXPORT void JNICALL Java_HelloNative_sayHello { printf("Hello,JNI"); }
四、生成dll共享库,而后Java程序load库,调用便可。
在Windows上,MinGW GCC 运行以下
gcc -m64 -Wl,--add-stdcall-alias -I"C:\Program Files\Java\jdk1.7.0_71\include" -I"C:\Program Files\Java\jdk1.7.0_71\include\include\win32" -shared -o HelloNative.dll HelloNative.c
-m64表示生成dll库是64位的。而后运行 HelloNative:
java HelloNative
终于成功地能够看到控制台打印以下:
Hello,JNI
3、JNI 调用 C 流程图
4、其余介绍
native是与C++联合开发的时候用的!java本身开发不用的!
使用native关键字说明这个方法是原生函数,也就是这个方法是用C/C++语言实现的,而且被编译成了DLL,由java去调用。
这些函数的实现体在DLL中,JDK的源代码中并不包含,你应该是看不到的。对于不一样的平台它们也是不一样的。这也是java的底层机制,实际上java就是在不一样的平台上调用不一样的native方法实现对操做系统的访问的。
1。native 是用作java 和其余语言(如c++)进行协做时用的也就是native 后的函数的实现不是用java写的
2。既然都不是java,那就别管它的源代码了,呵呵
native的意思就是通知操做系统,
这个函数你必须给我实现,由于我要使用。
因此native关键字的函数都是操做系统实现的,java只能调用。
java是跨平台的语言,既然是跨了平台,所付出的代价就是牺牲一些对底层的控制,而java要实现对底层的控制,就要一些其余语言的帮助,这个就是native的做用了
Java不是完美的,Java的不足除了体如今运行速度上要比传统的C++慢许多以外,Java没法直接访问到操做系统底层(如系统硬件等),为此Java使用native方法来扩展Java程序的功能。
能够将native方法比做Java程序同C程序的接口,其实现步骤:
1、在Java中声明native()方法,而后编译;
2、用javah产生一个.h文件;
3、写一个.cpp文件实现native导出方法,其中须要包含第二步产生的.h文件(注意其中又包含了JDK带的jni.h文件);
4、将第三步的.cpp文件编译成动态连接库文件;
5、在Java中用System.loadLibrary()方法加载第四步产生的动态连接库文件,这个native()方法就能够在Java中被访问了。
JAVA本地方法适用的状况
1.为了使用底层的主机平台的某个特性,而这个特性不能经过JAVA API访问
2.为了访问一个老的系统或者使用一个已有的库,而这个系统或这个库不是用JAVA编写的
3.为了加快程序的性能,而将一段时间敏感的代码做为本地方法实现。
一. 什么是Native Method
简单地讲,一个Native Method就是一个java调用非java代码的接口。一个Native Method是这样一个java的方法:该方法的实现由非java语言实现,好比C。这个特征并不是java所特有,不少其它的编程语言都有这一机制,好比在C++中,你能够用extern "C"告知C++编译器去调用一个C的函数。
"A native method is a Java method whose implementation is provided by non-java code."
在定义一个native method时,并不提供实现体(有些像定义一个java interface),由于其实现体是由非java语言在外面实现的。
标识符native能够与全部其它的java标识符连用,可是abstract除外。这是合理的,由于native暗示这些方法是有实现体的,只不过这些实现体是非java的,可是abstract却显然的指明这些方法无实现体。native与其它java标识符连用时,其意义同非Native Method并没有差异。
一个native method方法能够返回任何java类型,包括非基本类型,并且一样能够进行异常控制。这些方法的实现体能够自制一个异常而且将其抛出,这一点与java的方法很是类似。
native method的存在并不会对其余类调用这些本地方法产生任何影响,实际上调用这些方法的其余类甚至不知道它所调用的是一个本地方法。JVM将控制调用本地方法的全部细节。
若是一个含有本地方法的类被继承,子类会继承这个本地方法而且能够用java语言重写这个方法(这个彷佛看起来有些奇怪),一样的若是一个本地方法被fianl标识,它被继承后不能被重写。
本地方法很是有用,由于它有效地扩充了jvm。事实上,咱们所写的java代码已经用到了本地方法,在sun的java的并发(多线程)的机制实现中,许多与操做系统的接触点都用到了本地方法,这使得java程序可以超越java运行时的界限。有了本地方法,java程序能够作任何应用层次的任务。
2、使用方法
native关键字说明其修饰的方法是一个原生态方法,方法对应的实现不是在当前文件,而是在用其余语言(如C和C++)实现的文件中。Java语言自己不能对操做系统底层进行访问和操做,可是能够经过JNI接口调用其余语言来实现对底层的访问。
JNI是Java本机接口(Java Native Interface),是一个本机编程接口,它是Java软件开发工具箱(Java Software Development Kit,SDK)的一部分。JNI容许Java代码使用以其余语言编写的代码和代码库。Invocation API(JNI的一部分)能够用来将Java虚拟机(JVM)嵌入到本机应用程序中,从而容许程序员从本机代码内部调用Java代码。
不过,对Java外部的调用一般不能移植到其余平台,在applet中还可能引起安全异常。实现本地代码将使您的Java应用程序没法经过100%纯Java测试。可是,若是必须执行本地调用,则要考虑几个准则:
1.将您的全部本地方法都封装到一个类中,这个类调用单个的DLL。对每一种目标操做系统平台,均可以用特定于适当平台的版本的DLL。这样能够将本地代码的影响减小到最小,并有助于将之后所须要的移植问题考虑在内。
2.本地方法尽可能简单。尽可能使您的本地方法对第三方(包括Microsoft)运行时DLL的依赖减小到最小。使您的本地方法尽可能独立,以将加载您的DLL和应用程序所需的开销减小到最小。若是须要运行时DLL,必须随应用程序一块儿提供。
JNI的书写步骤以下:
如下是一个在Java中调用本地C程序的简单的例子:
a.编写HelloWorld.java类
class HelloWorld{ public native void hello(); static{ System.loadLibrary("hello"); } public static void main(String[] args){ new HelloWorld().hello(); } }
b.编译
javac HelloWorld.java
c.生成.h文件
javah -jni HelloWorld
生成内容以下:
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class HelloWorld */ #ifndef _Included_HelloWorld #define _Included_HelloWorld #ifdef __cplusplus extern "C" { #endif /* * Class: HelloWorld * Method: hello * Signature: ()V */ JNIEXPORT void JNICALL Java_HelloWorld_hello (JNIEnv *, jobject); #ifdef __cplusplus } #endif #endif
第一个参数是调用JNI方法时使用的JNI Environment指针。第二个参数是指向在此Java代码中实例化的Java对象HelloWorld的一个句柄。其余参数是方法自己的参数
d.c实现
#include <jni.h> #include "HelloWorld.h" #include <stdio.h> JNIEXPORT void JNICALL Java_HelloWorld_hello(JNIEnv *env,jobject obj){ printf("Hello World!\n"); return; }
其中,第一行是将jni.h文件引入(在%JAVA_HOME%\include目录下),里边有JNIEnv和jobject的定义。
e.编译c实现
这里以在Windows中为例,须要生成dll文件。在保存HelloWorldImpl.c文件夹下面,使用VC的编译器cl成。
cl -I%java_home%\include -I%java_home%\include\win32 -LD HelloWorldImp.c -Fehello.dll
注意:生成的dll文件名在选项-Fe后面配置,这里是hello,由于在HelloWorld.java文件中咱们loadLibary的时候使用的名字是hello。固然这里修改以后那里也须要修改。另外须要将-I%java_home%\include -I%java_home%\include\win32参数加上,由于在第四步里面编写本地方法的时候引入了jni.h文件。
f.运行程序
java HelloWorld就ok了!