一
.
什么是
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
中被访问了。