`
zhouwei064
  • 浏览: 26423 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类

JNI简易使用之使用vs命令提示下创建DLL详解

    博客分类:
  • Java
阅读更多
JNI是Java Native Interface的缩写,中文为JAVA本地调用。从Java1.1开始,Java Native Interface(JNI)标准成为java平台的一部分,它允许Java代码和其他语言写的代码进行交互。JNI一开始是为了本地已编译语言,尤其是C和C++而设计的,但是它并不妨碍你使用其他语言,只要调用约定受支持就可以了。
定义
使用java与本地已编译的代码交互,通常会丧失平台可移植性。但是,有些情况下这样做是可以接受的,甚至是必须的,比如,使用一些旧的库,与硬件、操作系统进行交互,或者为了提高程序的性能。JNI标准至少保证本地代码能工作在任何Java 虚拟机实现下。
设计目的
标准的java类库可能不支持你的程序所需的特性。或许你已经有了一个用其他语言写成的库或程序,而你希望在java程序中使用它。你可能需要用底层语言实现一个小型的时间敏感代码,比如汇编,然后在你的java程序中调用这些功能。


具体步骤
  • 编写带有native声明的方法的java类
  • 使用javac命令编译所编写的java类
  • 使用javah -jni java类名生成扩展名为h的头文件
  • 使用C/C++实现本地方法
  • 将C/C++编写的文件生成动态连接库
  • 导入DLL,运行程序

1.编写带有native声明的方法的java类
package jav.test.jni;

public class NativeTest {

	public static native void getHelloNative();
	
	static{
		System.loadLibrary("HelloNative");
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		getHelloNative();
	}

}

2.保存后,如果没有错误eclipse会编译产生HelloNative.class文件,默认在当前工程目录下D:\eclipse-workspace\javar\bin\jav\test\jni\NativeTest.class。
3.Core Java上说在生成h头文件之前要先生成CLASS文件 :,在D:\eclipse-workspace\javar\bin目录下生成了文件jav_test_jni_NativeTest.h;但实际操作中即使先前没有生成CLASS文件,也可以直接用javah对源文件生成头文件(先通过cd命令到达D:\eclipse-workspace\javar\src)
同样会生成文件jav_test_jni_NativeTest.h,只不过该文件在目录D:\eclipse-workspace\javar\src下产生的jav_test_jni_NativeTest.h文件如下:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class jav_test_jni_NativeTest */

#ifndef _Included_jav_test_jni_NativeTest
#define _Included_jav_test_jni_NativeTest
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     jav_test_jni_NativeTest
 * Method:    getHelloNative
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_jav_test_jni_NativeTest_getHelloNative
  (JNIEnv *, jclass);

#ifdef __cplusplus
}
#endif
#endif

4.写C文件(其实也可以用C++实现),实现jav_test_jni_NativeTest.h中的函数,这里请注意函数名,c文件里的函数名跟h文件的函数名要一致,若实现函数名跟上面例子的名字不一致虽然之后可以正确编译并产生dll,但是最终运行java程序链接的时候会出错,抛出java.lang.UnsatisfiedLinkError异常。我把该C源文件放在和头文件同一个目录下,即D:\eclipse-workspace\javar\bin下,因为该C文件里头调用了h头文件;如果不在同一个目录则会出现类似错误:
将C源文件放在和头文件同一个目录下,jav_test_jni_NativeTest.c内容如下(文件名称自定义,可以不同):
#include"jav_test_jni_NativeTest.h"
#include<stdio.h>
JNIEXPORT void JNICALL Java_jav_test_jni_NativeTest_getHelloNative
  (JNIEnv * env, jclass cl)
{
printf("Hello Java Native!");
}

关于C语言代码,我没有从VS2008中新建工程项目,事实上从头到尾就只有两个文件,一个是自动生成的头文件jav_test_jni_NativeTest.h,另外一个是实现头文件函数原型的c文件jav_test_jni_NativeTest.c,截屏如下:
5.编译c文件产生dll(这个地方容易出错,以下详述)。
在控制台下>cl   -I  %java_home%/include     -I   %java_home%/include/win32    -LD   源文件    -Fe目的文件
  • 第一,以上命令的参数中,-I(include的首字母大写)表示编译包含的额外目录,-LD表示产生dll,-Fe后面表示产生dll的名字,具体的参数可以自己用cl -help命令查看;
  • 第二,-Fe后面表示产生dll的名字,中间没有空格。
  • 第三,我这里用的是VS2008自带的“Visual Studio 2008命令提示"程序,实际上可在cmd调用即将要用到C/C++编译命令cl,其配置可以参考用vs2005编译器cl在控制台下编译。
  • 第四,其中的%表示是环境变量,这需要手动设置,虽然JAVA_HOME 目录已经在环境变量中设置成为jdk的安装目录,但是不管用。会报错,原因是没有加引号,如下:
  • 第五,如果改成绝对路径,但是没有对路径加引号,也会报错:
  • 第六,为保险起见,-LD后面的参数——源文件HelloNative.c,要用绝对路径,否则报错如下:
  • 第七,1》System.loadLibrary():若采用装载Windows\System32下或jdk\bin或Tomcat\bin目录下,或其他在PATH环境变量中定义的本地链接库,这依赖于当前操作系统;若只是将DLL文件加到工程根目录下,则只能从eclipse来运行,如果此时从cmd运行则报异常。2》System.load():根据具体的目录来加截本地链接库,必须是绝对路径。

这是我的编译结果:
如果成功编译,则会在C:\Program Files\Microsoft Visual Studio 9.0\VC目录生成如下四个文件:
后面的事情,就是将HelloNative.dll放到工程目录下面,即D:\eclipse-workspace\javar下面,但此时不能直接从cmd命令行运行NativeTest,会报错如下:

克服这个问题的方法是在C:\WINDOWS\system32,或者在PATH环境变量中定义其他目录下加入HelloNative.dll,运行结果如下:
如果是在Eclipse开发环境中运行HelloNative那就比较简单了,此时HelloNative.dll可以加入当前项目根目录下,即:

或者也可以在PATH环境变量中,定义的其他目录下加入HelloNative.dll,然后直接在eclipse中run,话说在调用代码中有静态代码块System.loadLibrary("HelloNative"); 自动加载刚才忙碌半天的DLL文件,从eclipse运行效果:
最后提示一下,一旦确定native方法所在源文件的包位置和类名称,就不能改变,否则就会抛出UnsatisfiedLinkError错误。

Review
Of course, this is not particularly impressive by itself. However, if you keep in mind that this message is generated by the C printf command and not by any Java programming language code, you will see that we have taken the first steps toward bridging the gap between the two languages!
In summary, you follow these steps to link a native method to a Java program:
  1. Declare a native method in a Java class and java to get .class file .
  2. Run javah to get a header file with a C declaration for the method.
  3. Implement the native method in C.
  4. Compile the C file and place the DLL in a shared library.
  5. Load that library in your Java program.



实验环境和使用工具
  • 测试平台:windows XP
  • Java相关:Eclipse SDK 3.4.2; jdk1.6.0_14
  • C相关:Microsoft Visual Studio 2008命令提示
  • cmd命令提示程序;Notepad++文本编辑器


参考文章:
  1. eclipse下jni初试
  2. 使用vs2005和eclipse 创建jni的helloworld
  3. 用vs2005编译器cl在控制台下编译
分享到:
评论
2 楼 shiyiqianxun 2012-08-20  
  
1 楼 zhouwei064 2012-08-20  
第一次发,请轻拍。。。

相关推荐

Global site tag (gtag.js) - Google Analytics