native總結

native關鍵字說明其修飾的方法是一個原生態方法,方法對應的實現不是在當前文件,而是在用其他語言(如C和C++)實現的文件中。Java語言本身不能對操作系統底層進行訪問和操作,但是可以通過JNI接口調用其他語言來實現對底層的訪問。

凡是一種語言,都希望是純。比如解決某一個方案都喜歡就單單這個語言來寫即可。Java平臺有個用戶和本地C代碼進行互操作的API,稱為Java Native Interface (Java本地接口)。

http://www.cnblogs.com/Alandre/p/4456719.html

創建一個Java類,里面包含著一個 native 的方法和加載庫的方法 loadLibrary。HelloNative.java 代碼如下:

native 關鍵字告訴編譯器(其實是JVM)調用的是該方法在外部定義,這里指的是C。

public class HelloNative

{static{System.loadLibrary("HelloNative");}public static native void sayHello();

@SuppressWarnings("static-access")

public static void main(String[] args){new HelloNative().sayHello();}}

那個加載庫的到后面也起作用。native 關鍵字告訴編譯器(其實是JVM)調用的是該方法在外部定義,這里指的是C。如果大家直接運行這個代碼,? JVM會告之:“A Java Exception has occurred.”控制臺輸出如下:Exception in thread "main" java.lang.UnsatisfiedLinkError: no HelloNative in java.library.path?at java.lang.ClassLoader.loadLibrary(Unknown Source)?at java.lang.Runtime.loadLibrary0(Unknown Source)?at java.lang.System.loadLibrary(Unknown Source)?at HelloNative.(HelloNative.java:5)

運行javah,得到包含該方法的C聲明頭文件.h ? ?->

根據頭文件,寫C實現本地方法 ?->

生成dll共享庫,然后Java程序load庫,調用即可。

HelloNative.h文件

/* DO NOT EDIT THIS FILE - it is machine generated */

#include

/* Header for class HelloNative */

#ifndef _Included_HelloNative

#define _Included_HelloNative

#ifdef __cplusplus

extern "C" {

#endif

/*

* Class:???? HelloNative

* Method:??? sayHello

* Signature: ()V

*/

JNIEXPORT void JNICALL Java_HelloNative_sayHello

(JNIEnv *, jclass);

#ifdef __cplusplus

}

#endif

#endif

jni.h 這個文件,在/%JAVA_HOME%include

3、根據頭文件,寫C實現本地方法

這里我們簡單地實現這個sayHello方法如下:

#include "HelloNative.h"

#include

JNIEXPORT void JNICALL Java_HelloNative_sayHello

{printf("Hello,JNI");}

生成dll共享庫,然后Java程序load庫,調用即可。在Windows上,MinGW GCC 運行如下:

gcc -m64? -Wl,--add-stdcall-alias -I"C:\Program Files\Java\jdk1.7.0_71\include" -I"C:\Program Files\Java\jdk1.7.0_71\include\include\win32" -shared -o HelloNative.dll HelloNative.c

-m64表示生成dll庫是64位的。然后運行HelloNative: java HelloNative

JNI調用C 流程

JNI是Java本機接口(JavaNativeInterface),是一個本機編程接口,它是Java軟件開發工具箱(JavaSoftware Development Kit,SDK)的一部分。JNI允許Java代碼使用以其他語言編寫的代碼和代碼庫。Invocation API(JNI的一部分)可以用來將Java虛擬機(JVM)嵌入到本機應用程序中,從而允許程序員從本機代碼內部調用Java代碼。

不過,對Java外部的調用通常不能移植到其他平臺,在applet中還可能引發安全異常。實現本地代碼將使您的Java應用程序無法通過100%純Java測試。但是,如果必須執行本地調用,則要考慮幾個準則:

1.將您的所有本地方法都封裝到一個類中,這個類調用單個的DLL。對每一種目標操作系統平臺,都可以用特定于適當平臺的版本的DLL。這樣可以將本地代碼的影響減少到最小,并有助于將以后所需要的移植問題考慮在內。

2.本地方法盡量簡單。盡量使您的本地方法對第三方(包括Microsoft)運行時DLL的依賴減少到最小。使您的本地方法盡量獨立,以將加載您的DLL和應用程序所需的開銷減少到最小。如果需要運行時DLL,必須隨應用程序一起提供。

JNI的書寫步驟如下:

a.編寫帶有native聲明的方法的Java

b.使用javac命令編譯編寫的Java

c.使用java-jni ****來生成后綴名為.h的頭文件

d.使用其他語言(C、C++)實現本地方法

e.將本地方法編寫的文件生成動態鏈接庫

以下是一個在Java中調用本地C程序的簡單的例子:

a.編寫HelloWorld.java

class HelloWorld{

publicnativevoid hello();

static{

System.loadLibrary("hello");

}

public static void main(String[] args){

new HelloWorld().hello();

}

}

聲明native方法:如果你想將一個方法做為一個本地方法的話,那么你就必須聲明改方法為native的,并且不能實現。其中方法的參數和返回值在后面講述。

Load動態庫:System.loadLibrary("hello");加載動態庫(我們可以這樣理解:我們的方法hello()沒有實現,但是我們在下面就直接使用了,所以必須在使用之前對它進行初始化)這里一般是以static塊進行加載的。同時需要注意的是System.loadLibrary();的參數“hello”是動態庫的名字。

b.編譯

javac HelloWorld.java

c.生成.h文件

javah -jni HelloWorld

示例比如說 類文件在D:\project\sparkStreamingLearn\src\main\java\TestNative\HelloWorldnative.java

使用javah 時注意執行位置是源代碼目錄 D:\project\sparkStreamingLearn\src\,

classpath是 載入類的路徑 是 D:\project\sparkStreamingLearn\src\main\java\

對應的類為:TestNative包下的HelloWorldnative.java? -jni 路徑是包名+類名 即 TestNative\HelloWorldnative.java

-d 輸出目錄(可以任意指定) 即TestNative_HelloWorldnative.h文件的輸出目錄 當前可以指定為D:\project\sparkStreamingLearn\src\main\java\TestNative\

結果為: D:\project\sparkStreamingLearn\src\main\java\TestNative\TestNative_HelloWorldnative.h

我們要開始寫javah的命令,以便生成對應的C語言頭文件

D:\我的文檔\workspace\PrepareForExam\src>javah -classpath D:\我的文檔\workspace\PrepareForExam\bin -d d:/ -jni

com.example.myclass.jni_test

其中java中各個命令的意思是

-classpath <路徑> 用于裝入類的路徑

-d <目錄> 輸出目錄

-jni 生成 JNI樣式的頭文件(默認)

注意到以上我們命令中指定的路徑

注意到我們的命令符的執行位置是源代碼目錄”D:\我的文檔\workspace\PrepareForExam\src”

-classpath? 后面的路徑是指包”com.example.myclass”所在的根路徑

-jni 后面的路徑是包名+類名

生成內容如下:

/* DO NOT EDIT THIS FILE - it is machine generated */

#include

/* Header for class HelloWorld */

#ifndef _Included_HelloWorld

#define _Included_HelloWorld

#ifdef __cplusplus

extern "C" {

#endif

/*

* Class:???? HelloWorld

* Method:????hello

* Signature: ()V

*/

JNIEXPORT void JNICALLJava_HelloWorld_hello

(JNIEnv *, jobject);

#ifdef __cplusplus

}

#endif

#endif

第一個參數是調用JNI方法時使用的JNI Environment指針。第二個參數是指向在此Java代碼中實例化的Java對象HelloWorld的一個句柄。其他參數是方法本身的參數

d.c實現

#include

#include "HelloWorld.h"

#include

JNIEXPORT void JNICALLJava_HelloWorld_hello(JNIEnv *env,jobject obj){

printf("Hello World!\n");

return;

}

其中,第一行是將jni.h文件引入(在%JAVA_HOME%\include目錄下),里邊有JNIEnv和jobject的定義。

e.編譯c實現

cl -- vs201X 的安裝目錄下 Common7/Tools/Shortcuts/VS2013開發人員命令提示? 開始cl 命令行? c/c++ 編譯器 ?這里以在Windows中為例,需要生成dll文件。在保存HelloWorldImpl.c文件夾下面,使用VC的編譯器cl成。是-I? 搜索其后添加所需文件所在的目錄 注意需要添加"" 即"java_home%\include" -LD? 是創建.dll

這里以在Windows中為例,需要生成dll文件。在保存HelloWorldImpl.c文件夾下面,使用VC的編譯器cl成。

cl -I%java_home%\include -I%java_home%\include\win32 -LD HelloWorldImp.c -Fehello.dll

注意:生成的dll文件名在選項-Fe后面配置,這里是hello,因為在HelloWorld.java文件中我們loadLibary的時候使用的名字是hello。當然這里修改之后那里也需要修改。另外需要將-I%java_home%\include -I%java_home%\include\win32參數加上,因為在第四步里面編寫本地方法的時候引入了jni.h文件。

6) 運行程序

javaHelloWorld就ok了!

javac? 出現錯誤 不是內部或外部命令,也不時可運行的程序? 修改path 添加 %Java_home%/bin;%Java_home%/jre/bin;

javac 出現中文亂碼 修改方法: javac -encoding "UTF-8" HelloWorldnative.java

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • native關鍵字說明其修飾的方法是一個原生態方法,方法對應的實現不是在當前文件,而是在用其他語言(如C和C++)...
    時待吾閱讀 1,158評論 0 1
  • 命題作文:對Java Native Interface (JNI) 有一個認識,使用JNI完成一個打印輸出的工作。...
    Silly_N_Fool閱讀 1,167評論 0 4
  • _ 聲明: 對原文格式以及內容做了細微的修改和美化, 主要為了方便閱讀和理解 _ 一. 基礎 Java Nativ...
    元亨利貞o閱讀 5,991評論 0 34
  • 一、NDK產生的背景 Android平臺從誕生起,就已經支持C、C++開發。眾所周知,Android的SDK基于J...
    Ten_Minutes閱讀 3,530評論 1 27
  • 2017-7-31 Whatever tickles your fancy 插一張畫 甚或會有很多人會有這樣那樣的...
    我是石老板閱讀 421評論 2 5