一. 什么是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语言在外面实现的。,下面给了一个示例: java
package java.lang; public class Object { ...... public final native Class<?> getClass(); public native int hashCode(); protected native Object clone() throws CloneNotSupportedException; public final native void notify(); public final native void notifyAll(); public final native void wait(long timeout) throws InterruptedException; ...... }
标识符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、使用方法app
native关键字说明其修饰的方法是一个原生态方法,方法对应的实现不是在当前文件,而是在用其余语言(如C和C++)实现的文件中。Java语言自己不能对操做系统底层进行访问和操做,可是能够经过JNI接口调用其余语言来实现对底层的访问。jvm
JNI是Java本机接口(Java Native Interface),是一个本机编程接口,它是Java软件开发工具箱(Java Software Development Kit,SDK)的一部分。JNI容许Java代码使用以其余语言编写的代码和代码库。Invocation API(JNI的一部分)能够用来将Java虚拟机(JVM)嵌入到本机应用程序中,从而容许程序员从本机代码内部调用Java代码。编程语言
不过,对Java外部的调用一般不能移植到其余平台,在applet中还可能引起安全异常。实现本地代码将使您的Java应用程序没法经过100%纯Java测试。可是,若是必须执行本地调用,则要考虑几个准则:ide
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了!