IT技术博客大学习 共学习 共进步

通过JNI实现Java对C/C++的调用

Elton's Blog 2011-07-30 21:25:17 浏览 3,043 次

JNI是Java Native Interface的缩写,中文为JAVA本地调用。从Java1.1开始,Java Native Interface(JNI)标准成为java平台的一部分,它允许Java代码和其他语言写的代码进行交互。JNI一开始是为了本地已编译语言,尤其是C和C++而设计的,但是它并不妨碍你使用其他语言,只要调用约定受支持就可以了。

大致步骤

  1. 编写带有native声明的方法的java类

  2. 使用javac命令编译所编写的java类

  3. 使用javah命令生成扩展名为h的头文件

  4. 使用C/C++实现本地方法

  5. 将C/C++编写的文件生成动态连接库

1) 编写java程序:

1
2
3
4
5
6
7
8
9
10
11
12
public class HelloNative{
  public native void greeting();//所有native所修饰的都是本地方法
 
  static{System.loadLibrary("HelloNative");//载入本地库
  }
 
  public static void main(String[] args){new HelloNative().greeting();//    System.out.println(System.getProperty("java.library.path"));
  }}

声明native方法:如果你想将一个方法做为一个本地方法的话,那么你就必须声明该方法为native的,并且不能实现。其中方法的参数和返回值在后面讲述。 Load动态库:System.loadLibrary(“HelloNative”);加载动态库(我们可以这样理解:我们的方法 greeting()没有实现,但是我们在下面就直接使用了,所以必须在使用之前对它进行初始化)这里一般是以static块进行加载的。同时需要注意的是System.loadLibrary();的参数“HelloNative”是动态库的名字。

2) 编译

1
javac HelloNative.java

3) 生成扩展名为h的头文件

1
javah HelloNative

命令执行后会在当前目录下生产一个c的头文件,名字为HelloNative.h。内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/* DO NOT EDIT THIS FILE - it is machine generated */#include <jni.h>/* Header for class HelloNative */
 
#ifndef _Included_HelloNative#define _Included_HelloNative#ifdef __cplusplusextern "C" {#endif/* * Class:     HelloNative * Method:    greeting * Signature: ()V */
JNIEXPORT void JNICALL Java_HelloNative_greeting
  (JNIEnv *, jobject);
 
#ifdef __cplusplus}#endif#endif

这个h文件相当于我们在java里面的接口,这里声明了一个 Java_HelloWorld_displayHelloWorld (JNIEnv *, jobject);方法,然后在我们的本地方法里面实现这个方法,也就是说我们在编写C/C++程序的时候所使用的方法名必须和这里的一致

4) 编写本地方法实现和由javah命令生成的头文件里面声明的方法名相同的方法。

1
2
3
4
5
6
7
8
9
#include <stdio.h>#include <jni.h>#include "HelloNative.h"
 
JNIEXPORT void JNICALL Java_HelloNative_greeting
  (JNIEnv * env, jobject obj){
  printf("Hello, Native!\n");}

5) 生成动态库

1
gcc -fPIC -I/home/elton/jdk/include -I/home/elton/jdk/include/linux -shared -o libHelloNative.so HelloNative.c

注意,必须告知编译器jni.h所在的接口位置。linux的动态库都是以lib开头,以.so结尾的,要遵守这个命名规范。-fPIC是告诉编译器生成跟位置无关的动态链接库
命令执行后,会在当前目录生成一个libHelloNative.so的动态链接库文件

6) 运行程序

1
java -Djava.library.path=. HelloNative

必须指定java.library.path变量的内容,告诉java你的动态链接库的位置。
或者在命令行上输入

1
export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH

这样就不用每次调试的时候都输入-Djava.library.path=.这个参数了。

当你部署的时候,你通过System.out.println(System.getProperty(“java.library.path”));得到你系统的java.library.path位置,然后把你的动态链接库拷贝到这个目录中。我用的是ubuntu 11.04 64位版本,得到的结果是

1
/usr/java/packages/lib/amd64:/usr/lib64:/lib64:/lib:/usr/lib

这样你的动态链接库就永远都会被java访问到了,不用每次指定环境变量了。

建议继续学习

  1. Java技术路线 (阅读 7,642)
  2. Java应用运维 (阅读 5,224)
  3. Java陷阱(2010版) (阅读 4,001)
  4. Java 常量值修改后不起作用 (阅读 3,902)
  5. Java的那些事儿 (阅读 3,762)
  6. Java将Object对象转换为String的总结合集 (阅读 3,703)
  7. Java泛型简明教程 (阅读 3,663)
  8. Eclipse Xtend对Java说:我帮你瘦身 (阅读 3,463)
  9. 五四陈透过PHP看JAVA系列:strtotime (阅读 3,243)
  10. 你应该更新的Java知识之Optional (阅读 2,983)