JAVA使用JNI调用C/C++动态库

来源:互联网 发布:mac 多因素方差分析 编辑:程序博客网 时间:2024/05/18 01:07

转自:http://blog.sina.com.cn/s/blog_4087649401012due.html


在实际使用中,我们经常会在JAVA和C/C++之间进行交互,比较通用的方法目前是使用JNI接口进行。

Native方法:

Java不是完美的,Java的不足除了体现在运行速度上要比传统的C++慢许多之外,Java无法直接访问到操作系统底层(如系统硬件等),为此Java使用native方法来扩展Java程序的功能。

  可以将native方法比作Java程序同C程序的接口,其实现步骤: 
  1、在Java中声明native()方法,然后编译; 
  2、用javah产生一个.h文件; 
  3、写一个.cpp文件实现native导出方法,其中需要包含第二步产生的.h文件(注意其中又包含了JDK带的jni.h文件); 
  4、将第三步的.cpp文件编译成动态链接库文件; 
  5、在Java中用System.loadLibrary()方法加载第四步产生的动态链接库文件,这个native()方法就可以在Java中被访问了。 
  JAVA本地方法适用的情况 
  1.为了使用底层的主机平台的某个特性,而这个特性不能通过JAVA API访问 
  2.为了访问一个老的系统或者使用一个已有的库,而这个系统或这个库不是用JAVA编写的 

  3.为了加快程序的性能,而将一段时间敏感的代码作为本地方法实现。

=====================================================

一.     什么是JNI?

JNI是Java Native Interface的缩写。从Java1.1开始,JNI标准成为Java平台的一部分。通过JNI,可以实现Java和其他的语言代码的交互,常用的是Java和C/C++之间的交互。

二.     JNI的使用方法

这里以Helloworld.java调用HelloWorld.dll/HelloWorld.so为例,讲述JNI的使用方法。

1.      创建一个class(HelloWorld.java),并声明一个native方法;

2.      使用javac编译该class(HelloWorld.java),生成HelloWorld.class;

3.      使用javah –jni生成C 头文件,其中包含native方法的原型。

4.      使用C/C++实现native方法(HelloWorld.c/ HelloWorld.cpp)。

5.      编译C代码(HelloWorld.c),创建动态库文件(HelloWorld.dll(for Windows)或者HelloWorld.so(for Linux));

6.      使用java类(HelloWorld.java),加载C动态库文件和native方法,实现二者交互。

下图是JNI的使用方法进行图例化解释:

 

 

三.     JNI应用实例

根据“二.JNI的使用方法”中介绍的步骤,我们做几个实例。

1.      简单的实例

1)      创建一个class,名称就用HelloWorld.java,并声明一个native方法;

public class HelloWorld {

    static {

        System.loadLibrary("HelloWorld");

    }

    private native void setMsg(String str);

    

    private native String getMsg();

 

    public static void main(String[] argv) {

        HelloWorld hw new HelloWorld();

        hw.setMsg("HelloWorld");

        System.out.println(hw.getMsg());

    }

}

2)      执行javac HelloWorld.java命令,生成HelloWorld.class;

3)      执行javah –jni HelloWorld命令,生成HelloWorld.h,其内容如下:

 

#include <jni.h>

 

 

#ifndef _Included_HelloWorld

#define _Included_HelloWorld

#ifdef __cplusplus

extern "C" {

#endif

 

JNIEXPORT void JNICALL Java_HelloWorld_setMsg

  (JNIEnv *, jobject, jstring);

 

 

JNIEXPORT jstring JNICALL Java_HelloWorld_getMsg

  (JNIEnv *, jobject);

 

#ifdef __cplusplus

}

#endif

#endif

需要注意的是Java中的类型发生了变化,另外native方法前面增加了前缀。

4)      创建HelloWorld.cpp文件,在此我们使用VC++6.0做成HelloWorld.cpp;

// HelloWorld.cpp Defines the entry point for the DLL application.

//

 

#include "stdafx.h"

#include "HelloWorld.h"

char far* str;

 

JNIEXPORT void JNICALL Java_HelloWorld_setMsg

(JNIEnv *env, jobject obj, jstring jstr) {

              str (char far*)env->GetStringUTFChars(jstr, NULL);

}

 

JNIEXPORT jstring JNICALL Java_HelloWorld_getMsg

(JNIEnv *env, jobject obj) {

              jstring jstr;

              jstr env->NewStringUTF(str);

              return jstr;

}

5)      编译HelloWorld.cpp,生成HelloWorld.dll;

6)      执行java HelloWorld命令,得到如下结果:

  

2.      带Package的实例

通常我们使用的source都是在某个Package中,这种情况下的处理稍有不同。还是以上面的示例为例,简单说明一下。

1)      创建一个class,名称就用HelloWorld.java,Package为jp.co.test,并声明一个native方法;

package jp.co.test;

 

public class HelloWorld {

    static {

        System.loadLibrary("HelloWorld");

    }

    private native void setMsg(String str);

    

    private native String getMsg();

 

    public static void main(String[] argv) {

        HelloWorld hw new HelloWorld();

        hw.setMsg("HelloWorld");

        System.out.println(hw.getMsg());

    }

}

2)      在jp/co/test/目录下使用javac HelloWorld.java命令,编译生成HelloWorld.class文件;

3)      此步稍有不同的是要在source Folder路径下执行javah jp.co.test.HelloWorld命令,执行成功后,也会在source Folder路径下生成jp_co_test_HelloWorld.h文件,其内容如下:

 

#include <jni.h>

 

 

#ifndef _Included_jp_co_test_HelloWorld

#define _Included_jp_co_test_HelloWorld

#ifdef __cplusplus

extern "C" {

#endif

 

JNIEXPORT void JNICALL Java_jp_co_test_HelloWorld_setMsg

  (JNIEnv *, jobject, jstring);

 

 

JNIEXPORT jstring JNICALL Java_jp_co_test_HelloWorld_getMsg

  (JNIEnv *, jobject);

 

#ifdef __cplusplus

}

#endif

#endif

 

4)      创建HelloWorld.cpp文件,native方法名要和jp_co_test_HelloWorld.h中的一致;

5)      编译HelloWorld.cpp,生成HelloWorld.dll;

6)      把HelloWorld.dll copy到source Folder路径下,执行java jp.co.test.HelloWorld得到如下结果:

 

 

四.     结束语

至此,JNI的基本使用方法介绍完了,但在实际使用中可能还会存在各种各样的问题,如其他操作系统(如:Linux)下的使用方法,传递中文字符的问题,传递复杂类型的问题等等,这需要大家不断深入探讨和钻研,方可熟练运用。