轉載請註明出處:
JNI全稱是Java Native Interface(Java本地接口)單詞首字母的縮寫,本地接口就是指用C和C++開發的接口。由於JNI是JVM規範中的一部份,因此可以將我們寫的JNI程序在任何實現了JNI規範的Java虛擬機中運行。同時,這個特性使我們可以複用以前用C/C++寫的大量代碼。
開發JNI程序會受到系統環境的限制,因爲用C/C++語言寫出來的代碼或模塊,編譯過程當中要依賴當前操作系統環境所提供的一些庫函數,並和本地庫鏈接在一起。而且編譯後生成的二進制代碼只能在本地操作系統環境下運行,因爲不同的操作系統環境,有自己的本地庫和CPU指令集,而且各個平臺對標準C/C++的規範和標準庫函數實現方式也有所區別。這就造成使用了JNI接口的JAVA程序,不再像以前那樣自由的跨平臺。如果要實現跨平臺,就必須將本地代碼在不同的操作系統平臺下編譯出相應的動態庫。
JNI開發流程主要分爲以下4步:
1、在eclipse中編寫聲明瞭native方法的Java類
2、生成JNI頭文件
3、在visual studio 中創建DLL 項目,實現 JNI頭文件中的方法
4、在eclipse中設置Native library location,路徑爲 visual studio 中生成的DLL 文件路徑,運行java 程序
通過上面的介紹,相信大家對JNI及開發流程有了一個整體的認識,下面通過一個HelloWorld的示例,再深入瞭解JNI開發的各個環節及注意事項。
第一步、在eclipse中新建一個HelloWorld.java
package com.study.jnilearn;
public class HelloWorld {
public static native String sayHello(String name); // 1.聲明這是一個native函數,由本地代碼實現
public static void main(String[] args) {
String text = sayHello("yangxin"); // 3.調用本地函數
System.out.println(text);
}
static {
System.loadLibrary("HelloWorld"); // 2.加載實現了native函數的動態庫,只需要寫動態庫的名字
}
}
第二步、生成JNI頭文件
1.配置 javah External tools
如圖點擊第二項 External tools Configurations
2.配置 如圖
${project_loc}/src
-classpath ${project_loc}/bin/classes -d ${project_loc}/jni -jni ${java_type_name}
3. 執行jExternal tools( javah)生成JNI 頭文件
第三步、用本地代碼實現.h頭文件中的函數
將第二步中生成的頭文件copy 過來
com_study_jnilearn_HelloWorld.h:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_study_jnilearn_HelloWorld */
#ifndef _Included_com_study_jnilearn_HelloWorld
#define _Included_com_study_jnilearn_HelloWorld
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_study_jnilearn_HelloWorld
* Method: sayHello
* Signature: (Ljava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_study_jnilearn_HelloWorld_sayHello
(JNIEnv *, jclass, jstring);
#ifdef __cplusplus
}
#endif
#endif
HelloWorld.c:
// HelloWorld.c
#include "com_study_jnilearn_HelloWorld.h"
#ifdef __cplusplus
extern "C"
{
#endif
/*
* Class: com_study_jnilearn_HelloWorld
* Method: sayHello
* Signature: (Ljava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_study_jnilearn_HelloWorld_sayHello(
JNIEnv *env, jclass cls, jstring j_str)
{
const char *c_str = NULL;
char buff[128] = { 0 };
c_str = (*env)->GetStringUTFChars(env, j_str, NULL);
if (c_str == NULL)
{
printf("out of memory.\n");
return NULL;
}
(*env)->ReleaseStringUTFChars(env, j_str, c_str);
printf("Java Str:%s\n", c_str);
sprintf(buff, "hello %s", c_str);
return (*env)->NewStringUTF(env, buff);
}
#ifdef __cplusplus
}
#endif
第六步、運行Java程序
Java在調用native(本地)方法之前,需要先加載動態庫。如果在未加載動態之前就調用native方法,會拋出找不到動態鏈接庫文件的異常。如下所示:
Exception in thread "main" java.lang.UnsatisfiedLinkError: com.study.jnilearn.HelloWorld.sayHello(Ljava/lang/String;)Ljava/lang/String;
at com.study.jnilearn.HelloWorld.sayHello(Native Method)
at com.study.jnilearn.HelloWorld.main(HelloWorld.java:9)
設置Native library location
通過ALT + ENTER 調出properties 選項卡
費了那麼大勁,終於可以運行寫好的Java程序了,結果如下:
Java Str:yangxin
hello yangxin
注意事項:
java 程序的版本和 dll 程序的版本要對上,例如x64的Java程序 需要編寫 x64的dll 動態庫