Linux下JNI的使用方法

来源:互联网 发布:java物流管理系统源码 编辑:程序博客网 时间:2024/06/05 21:18

         java是一门被广泛使用的语言,接触过大数据的都应该知道Hadoop和Spark,Hadoop就是用java编写的,虽然Spark采用的是Scala语言,其也提供对java语言的支持。有一些情况下,例如如果我们有大量原有的经过广泛测试的非 Java 代码,将它们全部用 Java 来重写,恐怕会带来巨大的工作量和长期的测试,在比方说如果我们的应用需要访问到特定的设备,甚至是仅符合公司内部信息交互规范的设备,或某个特定的操作系统才有的特性,这时Java 就显得有些力不从心了。为了应对类似的情况,Sun 公司在 JDK1.0 中就定义了 JNI(Java native interface) 规范,它规定了 Java 应用程序对本地方法的调用规则。

      另一方面,使用JNI也是有代价的。因为JAVA程序运行在JVM之上,具有平台无关的特点。但是如果Java程序通过JNI调用了原生的代码则Java程序就丧失了平台无关性。另外 JNI 调用非常耗时,一次大概要花 0.5 ~ 1 个毫秒,所以应用JNI要根据实际需求权衡利弊,做出选择。

下面通过一个简单的实例进行介绍JNI的使用方法。

(1)首先我们需要创建一个java程序。

public class HelloJni{            static{                         System.loadLibrary("hello");            }         public native void sayhello();         public static void main(String args[]){                       HelloJni hello = new HelloJni();                       hello.sayhello();   }}

在这个程序中我们声明了一个本地方法sayhello()方法,并加载了名为hello的动态链接库。

(2)编译HelloJni

使用javac命令生成HellJni.class文件,这个过程会检验程序是否有语法错误。

javac HelloJni

(3)生成.h文件

使用javah命令生成HelloJni.h文件,我们要根据这个文件编写本地方法也就是hello.cpp文件,注意在hello.cpp文件中要包含这个头文件

javah HelloJni

我们打开生成的这个.h文件,可以看到它里面已经声明好了我们需要实现的方法。其内容如下:

/* DO NOT EDIT THIS FILE - it is machine generated */#include <jni.h>/* Header for class HelloJni */#ifndef _Included_HelloJni#define _Included_HelloJni#ifdef __cplusplusextern "C" {#endif/* * Class:     HelloJni * Method:    sayhello * Signature: ()V */JNIEXPORT void JNICALL Java_HelloJni_sayhello  (JNIEnv *, jobject);#ifdef __cplusplus}#endif#endif

(4)编写cpp文件

#include "HelloJni.h"#include<iostream>using namespace std;JNIEXPORT void JNICALL Java_HelloJni_sayhello  (JNIEnv *, jobject){    cout << "Hello" << endl;    return;}

再次强调在这个文件中要包含HellJni.h这个头文件。

(5)生成动态链接库

生成动态链接库的命令另如下

g++ -fPIC -shared hello.cpp -o libhello.so  -I$JAVA_HOME/include -I$JAVA_HOME/include/linux 

 -fPIC -shared表示生成动态链接库,如果对这个参数不了解可以参考我的linux系统下使用gcc/g++编译生成动态库这篇文章。

下面详细说一下-I参数,它表示所编译文件引入的头文件的查找目录,这里主要是指定jni.h的查找目录$JAVA_HOME/include,但是如我们所见hello.cpp文件中并没有包含这个头文件,只有HelloJni.h和iostream这两个头文件,原因是在HelloJni.h中包含了jni.h,而iostream在默认的查找目录中所以不要管。

头文件的查找顺序为-I指定,然后是系统默认的查找目录/usr/include和/usr/local/include,如果你的程序中引入的头文件不在这两个目录中,就需要特别指定。

还有一件特别重要的事是设定动态链接库的路径,否则会出现如下错误。设定动态链接库的路径的方法我在inux系统下使用gcc/g++编译生成动态库这篇文章里也有介绍,请参阅。

Exception in thread "main" java.lang.UnsatisfiedLinkError: no hello in java.library.path
        at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1867)
        at java.lang.Runtime.loadLibrary0(Runtime.java:870)
        at java.lang.System.loadLibrary(System.java:1122)
        at HelloJni.<clinit>(HelloJni.java:10)


(6)执行java程序

在命令行输入命令java HelloJni执行java程序。



参考

https://www.ibm.com/developerworks/cn/java/l-linux-jni/

https://www.ibm.com/developerworks/cn/java/l-linux-jni/




原创粉丝点击