转自:http://blog.csdn.net/jtlyr/article/details/4389926
在实际使用中,我们经常会在JAVA和C/C++之间进行交互,比较通用的方法目前是使用JNI接口进行。
根据我在项目中使用的方法并结合icecreamchen的《JNI调用小结》,总结以下经验。
=====================================================
一. 什么是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的使用方法进行图例化解释:
图1 JNI使用方法
三. JNI应用实例
根据“二.JNI的使用方法”中介绍的步骤,我们做几个实例。
1. 简单的实例
1) 创建一个class,名称就用HelloWorld.java,并声明一个native方法;
public class HelloWorld {
static {
System.loadLibrary("HelloWorld");
}
private native void setMsg(String str);
private native String getMsg();
public static void main(String[] argv) {
HelloWorld hw = new HelloWorld();
hw.setMsg("HelloWorld");
System.out.println(hw.getMsg());
}
}
2) 执行javac HelloWorld.java命令,生成HelloWorld.class;
3) 执行javah –jni HelloWorld命令,生成HelloWorld.h,其内容如下:
/* 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: setMsg
* Signature: (Ljava/lang/String;)V
*/
JNIEXPORT void JNICALL Java_HelloWorld_setMsg
(JNIEnv *, jobject, jstring);
/*
* Class: HelloWorld
* Method: getMsg
* Signature: ()Ljava/lang/String;
*/
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方法;
package jp.co.test;
public class HelloWorld {
static {
System.loadLibrary("HelloWorld");
}
private native void setMsg(String str);
private native String getMsg();
public static void main(String[] argv) {
HelloWorld hw = new HelloWorld();
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文件,其内容如下:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include
/* Header for class jp_co_test_HelloWorld */
#ifndef _Included_jp_co_test_HelloWorld
#define _Included_jp_co_test_HelloWorld
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: jp_co_test_HelloWorld
* Method: setMsg
* Signature: (Ljava/lang/String;)V
*/
JNIEXPORT void JNICALL Java_jp_co_test_HelloWorld_setMsg
(JNIEnv *, jobject, jstring);
/*
* Class: jp_co_test_HelloWorld
* Method: getMsg
* Signature: ()Ljava/lang/String;
*/
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)下的使用方法,传递中文字符的问题,传递复杂类型的问题等等,这需要大家不断深入探讨和钻研,方可熟练运用。