. 什么是 Native Method
JNI Java Native Interface 的缩写,中文为 JAVA 本地调用。从 Java 1.1 开始, Java Native Interface JNI )标准成为 java 平台的一部分,它允许 Java 代码和其他语言写的代码进行交互。 JNI 一开始是为了本地已编译语言,尤其是 C C++ 而设计的,但是它并不妨碍你使用其他语言,只要调用约定受支持就可以了。
一个 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 与本地已编译的代码交互,通常会丧失平台可移植性。但是,有些情况下这样做是可以接受的,甚至是必须的,比如,使用一些旧的库,与硬件、操作系统进行交互,或者为了提高程序的性能。 JNI 标准至少保证本地代码能工作在任何 Java 虚拟机实现下。
 
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 程序可以做任何应用层次的任务。
------------------------------------------------------------------
 
编写带有 native 声明的方法的 java 类的步骤。
 
·使用 javac 命令编译所编写的 java
 
·使用 javah -jni java 类名生成扩展名为 h 的头文件
 
·使用 C/C++ 实现本地方法
 
·将 C/C++ 编写的文件生成动态连接库
 
· ok
 
1 编写 java 程序:这里以 HelloWorld 为例。
 
代码 1
 
public class HelloWorld {
 
public native void displayHelloWorld();
 
static {
 
System.loadLibrary("hello");
 
}
 
public static void main(String[] args){
 
new HelloWorld().displayHelloWorld();
 
}
 
}
 
声明 native 方法:如果你想将一个方法做为一个本地方法的话,那么你就必须声明改方法为 native 的,并且不能实现。其中方法的参数和返回值在后面讲述。 Load 动态库: System.loadLibrary (“ hello ”) ; 加载动态库(我们可以这样理解:我们的方法 displayHelloWorld ()没有实现,但是我们在下面就直接使用了,所以必须在使用之前对它进行初始化)这里一般是以 static 块进行加载的。同时需要注意的是 System.loadLibrary () ; 的参数“ hello ”是动态库的名字。
2 )编译
 
   没有什么好说的了 javac HelloWorld.java
 
3 )生成扩展名为 h 的头文件
 
   javah -jni HelloWorld
 
头文件的内容:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include
/* Header for class HelloWorld */
 
#ifndef _Included_HelloWorld
#define _Included_HelloWorld
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     HelloWorld
 * Method:    displayHelloWorld
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_HelloWorld_displayHelloWorld
  (JNIEnv *, jobject);
 
#ifdef __cplusplus
}
#endif
#endif
 
这里我们可以这样理解:这个 h 文件相当于我们在 java 里面的接口,这里声明了一个 Java_HelloWorld_displayHelloWorld JNIEnv * jobject ; 方法,然后在我们的本地方法里面实现这个方法,也就是说我们在编写 C/C++ 程序的时候所使用的方法名必须和这里的一致。
 
4 编写本地方法实现和由 javah 命令生成的头文件里面声明的方法名相同的方法。
以下没有试验:
代码 2
 
1 #include “jni.h”
2 #include “HelloWorld.h”
3 //#include other headers
4 JNIEXPORT void JNICALL Java_HelloWorld_displayHelloWorld JNIEnv *env jobject obj
 
{
 
printf (“ Hello world \n ”) ;
 
return;
 
}
 
注意代码 2 中的第 1 行,需要将 jni.h (该文件可以在 %JAVA_HOME%/include 文件夹下面找到)文件引入,因为在程序中的 JNIEnv jobject 等类型都是在该头文件中定义的;另外在第 2 行需要将 HelloWorld.h 头文件引入(我是这么理解的:相当于我们在编写 java 程序的时候,实现一个接口的话需要声明才可以,这里就是将 HelloWorld.h 头文件里面声明的方法加以实现。当然不一定是这样)。然后保存为 HelloWorldImp.c ok 了。
 
5 )生成动态库
 
这里以在 Windows 中为例,需要生成 dll 文件。在保存 HelloWorldImpl.c 文件夹下面,使用 VC 的编译器 cl 成。 cl (字母 L 的小写表示) -I (字母 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 文件。
 
6 运行程序 java HelloWorld ok.
 
另外:
可以将 native 方法比作 Java 程序同C程序的接口,其实现步骤:
1、在 Java 中声明 native() 方法,然后编译;
2、用 javah 产生一个 .h 文件;
3、写一个 .cpp 文件实现 native 导出方法,其中需要包含第二步产生的 .h 文件(注意其中又包含了 JDK 带的 jni.h 文件);
4、将第三步的 .cpp 文件编译成动态链接库文件;
5、在 Java 中用 System.loadLibrary() 方法加载第四步产生的动态链接库文件,这个 native() 方法就可以在 Java 中被访问了。