由于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,如下命令:
#gcc -I/usr/java/include -shared -o libHelloWorld.so HelloWorld.cpp
运行测试程序,发现不能导入.so文件,提示no HelloWorld 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 ”的美誉!但没违反重用性的规则。再者,需求来了,不这样实现能行吗?
首先,看一看首先,看一看win32下调用dll文件。
1, 新建HelloWorld.java
1
public class HelloWorld
2

{
3
static
4
{
5
try
6
{
7
//此处即为本地方法所在链接库名
8
System.loadLibrary("HelloWorld");
9
}catch(UnsatisfiedLinkError e)
{
10
System.err.println( "不能加载dll文件:/n " +e.toString() );
11
}
12
}//end static
13
public native void SayHello(String strName);
14
15
}
16
2, 编译java文件生成HelloWorld.class文件
public class HelloWorld2


{3
static4

{5
try6

{7
//此处即为本地方法所在链接库名8
System.loadLibrary("HelloWorld");9

}catch(UnsatisfiedLinkError e)
{10
System.err.println( "不能加载dll文件:/n " +e.toString() );11
}12
}//end static13
public native void SayHello(String strName);14

15
}16

3,在命令行下,javah -jni HelloWorld 生成 HelloWorld.h 文件
1
/**//* DO NOT EDIT THIS FILE - it is machine generated */
2
#include <jni.h>
3
/**//* Header for class HelloWorld */
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
JNIEXPORT void JNICALL Java_HelloWorld_SayHello
16
(JNIEnv *, jobject, jstring);
17
18
#ifdef __cplusplus
19
}
20
#endif
21
#endif
22
4, 编写HelloWorld.cpp
/**//* DO NOT EDIT THIS FILE - it is machine generated */2
#include <jni.h>3

/**//* Header for class HelloWorld */4

5
#ifndef _Included_HelloWorld6
#define _Included_HelloWorld7
#ifdef __cplusplus8
extern "C" {9
#endif10

/**//*11
* Class: HelloWorld12
* Method: SayHello13
* Signature: (Ljava/lang/String;)14
*/15
JNIEXPORT void JNICALL Java_HelloWorld_SayHello16
(JNIEnv *, jobject, jstring);17

18
#ifdef __cplusplus19
}20
#endif21
#endif22

1
#include <windows.h>
2
#include "HelloWorld.h"
3
#include <stdio.h>
4
//与Hello.h中函数声明相同
5
JNIEXPORT void JNICALL Java_HelloWorld_SayHello (JNIEnv * env, jobject arg, jstring instring)
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 WINAPI DllMain (HINSTANCE hInstance, DWORD fdwReason, PVOID pvReserved)
16

{
17
return TRUE ;
18
}
5, 在vc6下新建dll工程HelloWorld,加载HelloWorld.h和HelloWorld.cpp,编译生成HelloWorld.dll文件,最关键的是引用JAVAHOME/include/和JAVAHOME/include/win32的.h文件。
#include <windows.h>2
#include "HelloWorld.h"3
#include <stdio.h>4
//与Hello.h中函数声明相同5
JNIEXPORT void JNICALL Java_HelloWorld_SayHello (JNIEnv * env, jobject arg, jstring instring)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 WINAPI DllMain (HINSTANCE hInstance, DWORD fdwReason, PVOID pvReserved)16


{17
return TRUE ;18
}6,设置classpath为dll文件所在路径,新建一个测试类TestHelloWorldDLL.java
1
public class HelloWorld
{
2
public static void main(String args[])
{
3
HelloWorld hw = new HelloWorld();
4
hw.SayHello("Christmas");
5
}
6
}

public class HelloWorld
{2

public static void main(String args[])
{3
HelloWorld hw = new HelloWorld();4
hw.SayHello("Christmas"); 5
}6
}7, 输出结果: HelloWorld Christmas
=======================================================================================================
接下来,在linux下调用so试一试。
因为linux下不能用vc所以gcc,如下命令:
#gcc -I/usr/java/include -shared -o libHelloWorld.so HelloWorld.cpp
java -Djava.library.path=`pwd` -cp . MyNative再执行,ok了,输出正确结果!
最后,总结一下:
jni的使用很简单,麻烦的是抽象出所调用dll或so文件的接口封装成native方法。另外就是生成so或dll文件以后的路径很不好控制。最重要的一点Java 的C调用通常不能移植到其他平台上,失去了“write once,run anywhere ”的美誉!但没违反重用性的规则。再者,需求来了,不这样实现能行吗?
本文详细介绍了如何使用Java的JNI技术在Windows和Linux环境下调用C/C++代码。通过创建Java类,生成JNI头文件,编写C/C++实现,编译成DLL或SO文件,并进行测试,展示了具体步骤。虽然JNI调用可能影响Java的跨平台特性,但在特定需求下仍然是必要的解决方案。

1万+

被折叠的 条评论
为什么被折叠?



