由于java程序需要调用C或C++的代码,不得不使用JNI。C的代码在Win32和Linux下都有相同功能的不同实现,就像JDK分几种平台版本(win32,linux,solaris等)。
首先,看一看首先,看一看win32下调用dll文件。
1, 新建HelloWorld.java
3,在命令行下,javah -jni HelloWorld 生成 HelloWorld.h文件
6,设置classpath为dll文件所在路径,新建一个测试类TestHelloWorldDLL.java
7,输出结果: HelloWorld Christmas
=======================================================================================================
接下来,在linux下调用so试一试。
因为linux下不能用vc所以gcc,如下命令:
再执行,ok了,输出正确结果!
最后,总结一下:
jni的使用很简单,麻烦的是抽象出所调用dll或so文件的接口封装成native方法。另外就是生成so或dll文件以后的路径很不好控制。最重要的一点Java 的C调用通常不能移植到其他平台上,失去了“write once,run anywhere ”的美誉!但没违反重用性的规则。再者,需求来了,不这样实现能行吗?
首先,看一看首先,看一看win32下调用dll文件。
1, 新建HelloWorld.java
1
public
class
HelloWorld
2 {
3 static
4 {
5 try
6 {
7 // 此处即为本地方法所在链接库名
8 System.loadLibrary( " HelloWorld " );
9 } catch (UnsatisfiedLinkErrore) {
10 System.err.println( " 不能加载dll文件:\n " + e.toString());
11 }
12 } // endstatic
13 public native void SayHello(StringstrName);
14
15 }
16
2,编译java文件生成HelloWorld.class文件
2 {
3 static
4 {
5 try
6 {
7 // 此处即为本地方法所在链接库名
8 System.loadLibrary( " HelloWorld " );
9 } catch (UnsatisfiedLinkErrore) {
10 System.err.println( " 不能加载dll文件:\n " + e.toString());
11 }
12 } // endstatic
13 public native void SayHello(StringstrName);
14
15 }
16
3,在命令行下,javah -jni HelloWorld 生成 HelloWorld.h文件
1
/*
DONOTEDITTHISFILE-itismachinegenerated
*/
2 #include < jni.h >
3 /* HeaderforclassHelloWorld */
4
5 #ifndef_Included_HelloWorld
6 #define_Included_HelloWorld
7 #ifdef__cplusplus
8 extern"C"{
9 #endif
10 /*
11 *Class:HelloWorld
12 *Method:SayHello
13 *Signature:(Ljava/lang/String;)
14 */
15 JNIEXPORTvoidJNICALLJava_HelloWorld_SayHello
16 (JNIEnv * ,jobject,jstring);
17
18 #ifdef__cplusplus
19 }
20 #endif
21 #endif
22
4, 编写HelloWorld.cpp
2 #include < jni.h >
3 /* HeaderforclassHelloWorld */
4
5 #ifndef_Included_HelloWorld
6 #define_Included_HelloWorld
7 #ifdef__cplusplus
8 extern"C"{
9 #endif
10 /*
11 *Class:HelloWorld
12 *Method:SayHello
13 *Signature:(Ljava/lang/String;)
14 */
15 JNIEXPORTvoidJNICALLJava_HelloWorld_SayHello
16 (JNIEnv * ,jobject,jstring);
17
18 #ifdef__cplusplus
19 }
20 #endif
21 #endif
22
1
#include
<
windows.h
>
2 #include " HelloWorld.h "
3 #include < stdio.h >
4 // 与Hello.h中函数声明相同
5 JNIEXPORT void JNICALLJava_HelloWorld_SayHello(JNIEnv * env,jobjectarg,jstringinstring)
6 {
7 // 从instring字符串取得指向字符串UTF编码的指针
8 const jbyte * str =
9 ( const jbyte * )env -> GetStringUTFChars(instring,JNI_FALSE);
10 printf( " HelloWorld,%s\n " ,str);
11 // 通知虚拟机本地代码不再需要通过str访问Java字符串。
12 env -> ReleaseStringUTFChars(instring,( const char * )str);
13 return ;
14 }
15 int WINAPIDllMain(HINSTANCEhInstance,DWORDfdwReason,PVOIDpvReserved)
16 {
17 return TRUE;
18 }
5,在vc6下新建dll工程HelloWorld,加载HelloWorld.h和HelloWorld.cpp,编译生成HelloWorld.dll文件,最关键的是引用JAVAHOME\include\和JAVAHOME\include\win32的.h文件。
2 #include " HelloWorld.h "
3 #include < stdio.h >
4 // 与Hello.h中函数声明相同
5 JNIEXPORT void JNICALLJava_HelloWorld_SayHello(JNIEnv * env,jobjectarg,jstringinstring)
6 {
7 // 从instring字符串取得指向字符串UTF编码的指针
8 const jbyte * str =
9 ( const jbyte * )env -> GetStringUTFChars(instring,JNI_FALSE);
10 printf( " HelloWorld,%s\n " ,str);
11 // 通知虚拟机本地代码不再需要通过str访问Java字符串。
12 env -> ReleaseStringUTFChars(instring,( const char * )str);
13 return ;
14 }
15 int WINAPIDllMain(HINSTANCEhInstance,DWORDfdwReason,PVOIDpvReserved)
16 {
17 return TRUE;
18 }
6,设置classpath为dll文件所在路径,新建一个测试类TestHelloWorldDLL.java
1
public
class
HelloWorld
{
2 public static void main(Stringargs[]) {
3 HelloWorldhw = new HelloWorld();
4 hw.SayHello( " Christmas " );
5 }
6 }
2 public static void main(Stringargs[]) {
3 HelloWorldhw = new HelloWorld();
4 hw.SayHello( " Christmas " );
5 }
6 }
7,输出结果: HelloWorld Christmas
=======================================================================================================
接下来,在linux下调用so试一试。
因为linux下不能用vc所以gcc,如下命令:
#
gcc-I/usr/java/include-shared-olibHelloWorld.soHelloWorld.cpp
运行测试程序,发现不能导入.so文件,提示noHelloWorld in java.library.path,所以需要设置java.library.path。
java
-
Djava
.
library
.
path
=
`pwd`
-
cp
.
MyNative
注意我把.so文件拷到了当前路径,其他路径设置即可!
再执行,ok了,输出正确结果!
最后,总结一下:
jni的使用很简单,麻烦的是抽象出所调用dll或so文件的接口封装成native方法。另外就是生成so或dll文件以后的路径很不好控制。最重要的一点Java 的C调用通常不能移植到其他平台上,失去了“write once,run anywhere ”的美誉!但没违反重用性的规则。再者,需求来了,不这样实现能行吗?