JNI 开发流程

  • 编写声明了 native 方法的 Java 类
  • 将 Java 源代码编译成 class 字节码文件
  • 用 javah -jni 命令生成.h头文件(javah 是 jdk 自带的一个命令,-jni 参数表示将 class 中用native 声明的函数生成 JNI 规则的函数)
  • 用本地代码实现.h头文件中的函数
  • 将本地代码编译成动态库(Windows:_.dll,linux/unix:_.so,mac os x:\*.jnilib)
  • 拷贝动态库至 java.library.path 本地库搜索目录下,并运行 Java 程序

HelloWorld例程

1.新建一个 HelloWorld.java 源文件
package com.win.jni;

public class HelloWorld {

    public static void main(String[] args){
        System.out.println(sayHello("MorrisWare"));
    }

    public static native String sayHello(String name);

    static {
        System.loadLibrary("HelloWorld");
    //System.load("/home/morrisware/JNI/HelloWorld/lib/libHelloWorld.so"
    }
}
2.用 javac 命令将.java源文件编译成.class字节码文件
➜  HelloWorld mkdir bin
➜  HelloWorld javac src/com/win/jni/HelloWorld.java -d ./bin/

-d 表示将编译后的 class 文件放到指定的目录下

3.用 javah -jni 命令,根据class字节码文件生成.h头文件(-jni 参数是可选的)
➜  HelloWorld mkdir jni
➜  HelloWorld javah -jni -classpath ./bin/ -d jni com.win.jni.HelloWorld

-classpath 类搜索路径,这里表示从当前的 bin 目录下查找

-d 将生成的头文件放到当前的 jni 目录下

4.用本地代码实现.h头文件中的函数
  • com_win_jni_HelloWorld.h
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_win_jni_HelloWorld */

#ifndef _Included_com_win_jni_HelloWorld
#define _Included_com_win_jni_HelloWorld
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_win_jni_HelloWorld
 * Method:    sayHello
 * Signature: (Ljava/lang/String;)Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_win_jni_HelloWorld_sayHello
  (JNIEnv *, jclass, jstring);

#ifdef __cplusplus
}
#endif
#endif
  • com_win_jni_HelloWorld.c
#include "com_win_jni_HelloWorld.h"

#ifdef __cplusplus
extern "C" {
#endif
/*
 *  * Class:     com_win_jni_HelloWorld
 *   * Method:    sayHello
 *    * Signature: (Ljava/lang/String;)Ljava/lang/String;
 *     */
JNIEXPORT jstring JNICALL Java_com_win_jni_HelloWorld_sayHello
          (JNIEnv *env, jclass type, jstring name_){
    const char *name = (*env)->GetStringUTFChars(env,name_,0);
    char buff[100];
    if(name == NULL){
        printf("out of memory.\n");
        return;
    }
    printf("Java Str:%s\n",name);
    sprintf(buff,"hello %s",name);
    (*env)->ReleaseStringUTFChars(env,name_,name);
    return (*env)->NewStringUTF(env,buff);
}

#ifdef __cplusplus
}
#endif
5.将 C/C++ 代码编译成本地动态库文件动态库文件名命名规则:lib+动态库文件名+后缀(操作系统不一样,后缀名也不一样)如:
  • Mac OS X : libHelloWorld.jnilib
  • Windows :HelloWorld.dll(不需要 lib 前缀)
  • Linux/Unix:libHelloWorld.so

Linux/Unix

➜  HelloWorld mkdir lib
➜  jni gcc -I$JAVA_HOME/include -I$JAVA_HOME/include/linux -fPIC -shared 
com_win_jni_HelloWorld.c -o ../lib/libhello.so

参数说明:

  • -I: 包含编译JNI必要的头文件
  • -fPIC: 编译成与位置无关的独立代码
  • -shared:编译成动态库
  • -o: 指定编译后动态库生成的路径和文件名
6.运行 Java 程序
  • 加载动态库
System.loadLibrary("hello");  
System.load("/home/morrisware/JNI/HelloWorld/lib/libhello.so");
  • 让 Java 从 java.library.path 找到动态链接库文件
 java -Djava.library.path=/home/morrisware/JNI/HelloWorld/lib -classpath ./bin com.win.jni.HelloWorld

results matching ""

    No results matching ""