Hello JNI

December 16, 2011 / Java, JNI, Linux

1. 编写Java类

定义一个 Java 类HelloNative,为使用的本地方法编写方法声明,指定 native 关键字,HelloNative.java如下所示:

public class HelloNative {
    public native void print(String s);

    static {
        try {
            System.loadLibrary("HelloNative");
        } catch(UnsatisfiedLinkError e) {
            System.err.println( "Cannot load hello library:\n " +
                e.toString() );
        }
    }

    public static void main(String[] args) {
        new HelloNative().print("Hello World!!!");
    }
}

编写后Java代码后要编译HelloNative类:

javac HelloNative.java

2. 编写本地方法

接下来要为以上定义的类编写Java本地接口头文件,可以使用javah来生成对应的头文件:

javah HelloNative

生成的HelloNative.h如下所示:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class HelloNative */

#ifndef _Included_HelloNative
#define _Included_HelloNative
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class:     HelloNative
* Method:    print
* Signature: (Ljava/lang/String;)V
*/
JNIEXPORT void JNICALL Java_HelloNative_print
  (JNIEnv *, jobject, jstring);

#ifdef __cplusplus
}
#endif
#endif

下面对头文件中定义的函数进行实现,HelloNative.cpp如下所示

#include "HelloNative.h"
#include <stdio.h>
JNIEXPORT void JNICALL Java_HelloNative_print
    (JNIEnv * env, jobject arg, jstring instr) {
    // get the pointer pointed to UTF encoding string from instr.
    const char *str =
        (const char *)env -> GetStringUTFChars(instr, JNI_FALSE);
    printf("%s\n",str);
    // inform the jvm that the native code doesn't need to
    // access Java String by str.
    env -> ReleaseStringUTFChars(instr, str);   
    return;
}

其中env指针指向一个函数指针表;jobject指向java中的java对象,相当于this;instr是从Java代码传递过来的String类对象,在本地代码中不能直接读取,需要使用GetStringUTFChars函数进行转换。

3. 编译共享库

编译生成目标文件HelloNative.o:

gcc -fPIC -I$JAVA_HOME/include -I$JAVA_HOME/include/linux -c HelloNative.cpp

编译生成共享库libHelloNative.so.1.0:

gcc -shared -Wl,-soname,libHelloNative.so.1 -o libHelloNative.so.1.0 HelloNative.o
cp libHelloNative.so.1.0 libHelloNative.so

4. 运行

添加共享库所在目录到LD_LIBRARY_PATH环境变量中:

export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH
java HelloNative

或者在运行时设置java的环境变量java.library.path:

java -Djava.library.path=. HelloNative

5. 后记

关于文中用到或未用到的函数或类型说明,请详见参考资料。文中若有错误或疏漏之处,烦请批评指正。

6. 参考资料

  1. 《Java2核心技术》第七版, 第二卷, 第11章, 本地方法.

  2. 在 Linux 平台下使用 JNI: http://www.ibm.com/developerworks/cn/java/l-linux-jni/