Java通过JNI调用C语言的方法

丁一鸣的CSDN 2010-05-26

Java通过JNI调用本地方法,而本地方法是以库文件的形式存放的(在WINDOWS平台上是DLL文件形式,在UNIX机器上是SO文件形式)。通过调用本地的库文件的内部方法,使Java可以实现和本地机器的紧密联系,调用系统级的各接口方法。

简单介绍及应用如下:

一、Java中所需要做的工作

在Java程序中,首先需要在类中声明所调用的库名称,如下:

Java代码

1.static {

2.System.loadLibrary(“goodluck”);

3.}

4.static {

5.System.loadLibrary(“goodluck”);

6.}

在这里,库的扩展名字可以不用写出来,究竟是DLL还是SO,由系统自己判断。

还需要对将要调用的方法做本地声明,关键字为native。并且只需要声明,而不需要具体实现。如下:

Java代码

7.public native static void set(int i);

8.public native static int get();

9.public native static void set(int i);

10.public native static int get();

然后编译该Java程序文件,生成CLASS,再用JavaH命令,JNI就会生成C/C++的头文件。

例如程序testdll.Java,内容为:

Java代码

11.public class testdll

12.{

13.static

14.{

15.System.loadLibrary("goodluck");

16.}

17.public native static int get();

18.public native static void set(int i);

19.public static void main(String[] args)

20.{

21.testdll test = new testdll();

22.test.set(10);

23.System.out.println(test.get());

24.}

25.}

26.public class testdll

27.{

28.static

29.{

30.System.loadLibrary("goodluck");

31.}

32.public native static int get();

33.public native static void set(int i);

34.public static void main(String[] args)

35.{

36.testdll test = new testdll();

37.test.set(10);

38.System.out.println(test.get());

39.}

40.}

用Javac testdll.Java编译它,会生成testdll.class。

再用Javah testdll,则会在当前目录下生成testdll.h文件,这个文件需要被C/C++程序调用来生成所需的库文件。

二、C/C++中所需要做的工作

对于已生成的.h头文件,C/C++所需要做的,就是把它的各个方法具体的实现。然后编译连接成库文件即可。再把库文件拷贝到Java程序的路径下面,就可以用Java调用C/C++所实现的功能了。

接上例子。我们先看一下testdll.h文件的内容:

Java代码

41./* DO NOT EDIT THIS FILE - it is machine generated */

42.#include

43.

44./* Header for class testdll */

45.

46.#ifndef _Included_testdll

47.

48.#define _Included_testdll

49.

50.#ifdef __cplusplus

51.

52.extern "C" {

53.

54.#endif

55.

56./*

57.

58.* Class: testdll

59.

60.* Method: get

61.

62.* Signature: ()I

63.

64.*/

65.

66.JNIEXPORT jint JNICALL Java_testdll_get

67.

68.(JNIEnv *, jclass);

69.

70./*

71.

72.* Class: testdll

73.

74.* Method: set

75.

76.* Signature: (I)V

77.

78.*/

79.

80.JNIEXPORT void JNICALL Java_testdll_set

81.

82.(JNIEnv *, jclass, jint);

83.

84.#ifdef __cplusplus

85.

86.}

87.

88.#endif

89.

90.#endif

91.

92./* DO NOT EDIT THIS FILE - it is machine generated */

93.#include

94.

95./* Header for class testdll */

96.

97.#ifndef _Included_testdll

98.

99.#define _Included_testdll

100.

101.#ifdef __cplusplus

102.

103.extern "C" {

104.

105.#endif

106.

107./*

108.

109.* Class: testdll

110.

111.* Method: get

112.

113.* Signature: ()I

114.

115.*/

116.

117.JNIEXPORT jint JNICALL Java_testdll_get

118.

119.(JNIEnv *, jclass);

120.

121./*

122.

123.* Class: testdll

124.

125.* Method: set

126.

127.* Signature: (I)V

128.

129.*/

130.

131.JNIEXPORT void JNICALL Java_testdll_set

132.

133.(JNIEnv *, jclass, jint);

134.

135.#ifdef __cplusplus

136.

137.}

138.

139.#endif

140.

141.#endif

在具体实现的时候,我们只关心两个函数原型 :

Java代码

JNIEXPORT jint JNICALL Java_testdll_get (JNIEnv *, jclass);

JNIEXPORT jint JNICALL Java_testdll_get (JNIEnv *, jclass);

和Java代码

JNIEXPORT void JNICALL Java_testdll_set (JNIEnv *, jclass, jint);

JNIEXPORT void JNICALL Java_testdll_set (JNIEnv *, jclass, jint);

这里JNIEXPORT和JNICALL都是JNI的关键字,表示此函数是要被JNI调用的。而jint是以JNI为中介使Java的int类型与本地的int沟通的一种类型,我们可以视而不见,就当做int使用。函数的名称是Java_再加上Java程序的package路径再加函数名组成的。参数中,我们也只需要关心在Java程序中存在的参数,至于JNIEnv*和jclass我们一般没有必要去碰它。

好,下面我们用testdll.cpp文件具体实现这两个函数:

Java代码

142.#include "testdll.h"

143.int i = 0;

144.JNIEXPORT jint JNICALL Java_testdll_get (JNIEnv *, jclass)

145.{

146.return i;

147.}

148.JNIEXPORT void JNICALL Java_testdll_set (JNIEnv *, jclass, jint j)

149.{

150.i = j;

151.}

152.#include "testdll.h"

153.int i = 0;

154.JNIEXPORT jint JNICALL Java_testdll_get (JNIEnv *, jclass)

155.{

156.return i;

157.}

158.JNIEXPORT void JNICALL Java_testdll_set (JNIEnv *, jclass, jint j)

159.{

160.i = j;

161.}

编译连接成库文件,本例是在WINDOWS下做的,生成的是DLL文件。并且名称要与Java中需要调用的一致,这里就是goodluck.dll

把goodluck.dll拷贝到testdll.class的目录下,Java testdll运行它,就可以观察到结果了。

相关推荐