在实际使用中,我们经常会在JAVA和C/C++之间进行交互,比较通用的方法目前是使用JNI接口进行。
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.为了加快程序的性能,而将一段时间敏感的代码作为本地方法实现。
=====================================================
一. 什么是JNI?
JNI是Java Native Interface的缩写。从Java1.1开始,JNI标准成为Java平台的一部分。通过JNI,可以实现Java和其他的语言代码的交互,常用的是Java和C/C++之间的交互。
二. JNI的使用方法
这里以Helloworld.java调用HelloWorld.dll/HelloWorld.so为例,讲述JNI的使用方法。
1. 创建一个class(HelloWorld.java),并声明一个native方法;
2. 使用javac编译该class(HelloWorld.java),生成HelloWorld.class;
3. 使用javah –jni生成C 头文件,其中包含native方法的原型。
4. 使用C/C++实现native方法(HelloWorld.c/ HelloWorld.cpp)。
5. 编译C代码(HelloWorld.c),创建动态库文件(HelloWorld.dll(for Windows)或者HelloWorld.so(for Linux));
6. 使用java类(HelloWorld.java),加载C动态库文件和native方法,实现二者交互。
下图是JNI的使用方法进行图例化解释:
三. JNI应用实例
根据“二.JNI的使用方法”中介绍的步骤,我们做几个实例。
1. 简单的实例
1) 创建一个class,名称就用HelloWorld.java,并声明一个native方法;
publicclassHelloWorld {
static{
System.loadLibrary("HelloWorld");
}
privatenativevoidsetMsg(String str);
privatenativeString getMsg();
publicstaticvoidmain(String[] argv) {
HelloWorld hw = newHelloWorld();
hw.setMsg("HelloWorld");
System.out.println(hw.getMsg());
}
}
2) 执行javac HelloWorld.java命令,生成HelloWorld.class;
3) 执行javah –jni HelloWorld命令,生成HelloWorld.h,其内容如下:
#include <jni.h>
#ifndef _Included_HelloWorld
#define _Included_HelloWorld
#ifdef __cplusplus
extern "C" {
#endif
JNIEXPORT void JNICALL Java_HelloWorld_setMsg
(JNIEnv *, jobject, jstring);
JNIEXPORT jstring JNICALL Java_HelloWorld_getMsg
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
需要注意的是Java中的类型发生了变化,另外native方法前面增加了前缀。
4) 创建HelloWorld.cpp文件,在此我们使用VC++6.0做成HelloWorld.cpp;
// HelloWorld.cpp : Defines the entry point for the DLL application.
//
#include "stdafx.h"
#include "HelloWorld.h"
char far* str;
JNIEXPORT void JNICALL Java_HelloWorld_setMsg
(JNIEnv *env, jobject obj, jstring jstr) {
str = (char far*)env->GetStringUTFChars(jstr, NULL);
}
JNIEXPORT jstring JNICALL Java_HelloWorld_getMsg
(JNIEnv *env, jobject obj) {
jstring jstr;
jstr = env->NewStringUTF(str);
return jstr;
}
5) 编译HelloWorld.cpp,生成HelloWorld.dll;
6) 执行java HelloWorld命令,得到如下结果:
2. 带Package的实例
通常我们使用的source都是在某个Package中,这种情况下的处理稍有不同。还是以上面的示例为例,简单说明一下。
1) 创建一个class,名称就用HelloWorld.java,Package为jp.co.test,并声明一个native方法;
packagejp.co.test;
publicclassHelloWorld {
static{
System.loadLibrary("HelloWorld");
}
privatenativevoidsetMsg(String str);
privatenativeString getMsg();
publicstaticvoidmain(String[] argv) {
HelloWorld hw = newHelloWorld();
hw.setMsg("HelloWorld");
System.out.println(hw.getMsg());
}
}
2) 在jp/co/test/目录下使用javac HelloWorld.java命令,编译生成HelloWorld.class文件;
3) 此步稍有不同的是要在source Folder路径下执行javah jp.co.test.HelloWorld命令,执行成功后,也会在source Folder路径下生成jp_co_test_HelloWorld.h文件,其内容如下:
#include <jni.h>
#ifndef _Included_jp_co_test_HelloWorld
#define _Included_jp_co_test_HelloWorld
#ifdef __cplusplus
extern "C" {
#endif
JNIEXPORT void JNICALL Java_jp_co_test_HelloWorld_setMsg
(JNIEnv *, jobject, jstring);
JNIEXPORT jstring JNICALL Java_jp_co_test_HelloWorld_getMsg
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
4) 创建HelloWorld.cpp文件,native方法名要和jp_co_test_HelloWorld.h中的一致;
5) 编译HelloWorld.cpp,生成HelloWorld.dll;
6) 把HelloWorld.dll copy到source Folder路径下,执行java jp.co.test.HelloWorld得到如下结果:
四. 结束语
至此,JNI的基本使用方法介绍完了,但在实际使用中可能还会存在各种各样的问题,如其他操作系统(如:Linux)下的使用方法,传递中文字符的问题,传递复杂类型的问题等等,这需要大家不断深入探讨和钻研,方可熟练运用。