c调用其他类的方法_Java 的 Native 方法——今天又进步了
1. 簡介
1.1 個人理解
初次遇見 native 是在 java.lang.String 源碼中的一個 intern 方法:
public?native?String?intern();因為還是第一次遇到,所以就去搜了一些文章進行了解。下面就對一些 Native 關鍵字進行一些總結。
native 也即 JNI —— Java Native Interface(Java 本地接口)。凡是一種語言,都希望是純的。比如解決某一個方案就單單使用同一個語言來實現。而 Java 卻不然,Java 平臺有個用戶和本地 C 代碼進行相互操作的 API,稱為 Java Native Interface (Java 本地接口)。也就是說,相當于使用 Java 語言聲明了一個方法,而這個方法的具體實現是在其他語言(如 C、C++等)中實現的,所以 Java 中編寫的也就類似于一個接口,只是這個接口被稱作本地接口。
Java 使用本地接口也是有原因的,因為 Java 的平臺無關性,有優勢當然也有犧牲,它的缺點就是不能使用 Java 代碼直接對一些底層進行操作,但是對底層的操作又是一個語言必不可少的,于是 Java 就想到了間接去操作底層,而中間利用的就是操作系統。所以有些方法,Java 聲明為了 native ,具體的實現是在 DLL 中,JVM 去進行真正的操作。
「簡單記憶:native 方法是 Java 中聲明,由操作系統中具體方法實現。」
1.2 其他介紹
網友見解:
- native 是與 C++ 聯合開發的時候用的!java 自己開發不用的!
- 使用 native 關鍵字說明這個方法是「原生函數」,也就是這個方法是用 C/C++ 語言實現的,并且被編譯成了 DLL,由 Java去調用。這些函數的實現體在 DLL 中,JDK 的源代碼中并不包含,你應該是看不到的。對于不同的平臺它們也是不同的。這也是 Java 的底層機制,實際上 Java 就是在不同的平臺上調用不同的 native 方法實現對操作系統的訪問的。
- native 是用做 java 和其他語言(如c++)進行協作時用的也就是 native 后的函數的實現不是用 Java 寫的,既然都不是 Java,那就別管它的源代碼了,呵呵。
- native 的意思就是通知操作系統,這個函數你必須給我實現,因為我要使用。所以 native 關鍵字的函數都是操作系統實現的,Java 只能調用。
- Java 是跨平臺的語言,既然是跨了平臺,所付出的代價就是犧牲一些對底層的控制,而 Java 要實現對底層的控制,就需要一些其他語言的幫助,這個就是 native 的作用了
- Java 不是完美的,Java 的不足除了體現在運行速度上要比傳統的 C++ 慢許多之外,Java 無法直接訪問到操作系統底層(如系統硬件等),為此 Java 使用 native 方法來擴展 Java 程序的功能。
Java 本地方法適用的情況:
2. 用 Java 調用 C 的實例
為了更好的理解 Java 中調用 Native 方法,特來編寫一個具體的小的測試。
以下所有文件都存于個人本地文件夾:C:\Users\Eric\Desktop\NativeTest。
2.1 創建包含本地方法的類
在文件夾下創建一個 HelloNative.java 文件,里面包含著一個 native 的方法和加載庫的方法 loadLibrary。代碼如下:
public?class?HelloNative?{????static?{
????????//?注意加載庫的名字為?HelloNative,需要與下文的生成文件保持一致
????????System.loadLibrary("HelloNative");
????}
?????
????public?static?native?void?sayHello();
?????
????@SuppressWarnings("static-access")
????public?static?void?main(String[]?args)?{
????????new?HelloNative().sayHello();
????}
}
首先注意的是 native 方法,然后那個加載庫的靜態代碼塊在后面也起作用。native 關鍵字告訴編譯器(其實是 JVM)調用的是該方法在外部定義,這里指的是 C。
2.2 編譯運行
在當前文件夾下使用 CMD 命令行編譯 HelloNative.java,如下。
如果當前類中沒有 Native 方法,那么我們可以直接使用 java 命令直接運行,但是此時大家直接運行這個代碼,會出現以下結果:
意思是虛擬機說不知道如何找到 sayHello。因為我們定義的 sayHello 方法為 native 類型,所以我們還需要再進行下文的操作步驟。
2.3 獲得頭文件
在當前文件目錄下運行 javah,得到包含該方法的 C 聲明頭文件 。命令如下:
javah HelloNative # 生成 .h文件得到的結果如下:
得到的 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
這個頭文件中可以看見我們聲明的 Java 本地化 sayHello 方法,對應 C 的聲明:JNIEXPORT void JNICALL Java_HelloNative_sayHello(JNIEnv *, jclass);,我們只要實現這個方法即可。
注意:頭文件中 jni.h 這個文件,是在本地 JDK 目錄下的 include 文件夾中,例如我的目錄:
2.3 C 實現頭文件的聲明方法
生成了頭文件之后,我們再在當前文件夾下創建一個 HelloNative.c 文件,并簡單地實現 HelloNative.h 文件中聲明的 sayHello 方法,代碼如下:
//?包含剛才生成的.h文件#include?"HelloNative.h"
#include?
JNIEXPORT?void?JNICALL?Java_HelloNative_sayHello(JNIEnv?*env,?jclass?thisClass)?{
????printf("Hello,?Native!!");
}
結果:
2.4 生成動態鏈接庫
到了這一步,我們需要將上述兩個文件 HelloNative.c 和 HelloNative.h 編譯為動態鏈接庫。
這里說明「兩種」方法:分步編譯或一次性編譯形成動態鏈接庫文件。
「(1)一次性編譯」
在 Windows CMD 命令行里,使用如下命令:
gcc -m64 -Wl,--add-stdcall-alias -I"C:/Program Files/Java/jdk1.8.0_181/include" -I"C:/Program Files/Java/jdk1.8.0_181/include/win32" -shared -o HelloNative.dll HelloNative.c注意:上述 JDK 為個人本地路徑,需要根據個人情況進行修改。-m64 表示生成 dll 庫是 64 位的,參數 -I 指定頭文件路徑上述命令運行后,我們會在目錄文件夾下生成相應的動態鏈接庫文件,如下:
?如果使用的 Windows 上面沒有 gcc,需要先下載壓縮包然后配置一下環境變量即可使用(兩分鐘就搞定),壓縮包及配置步驟,這里推薦一條有關的配置博文:https://blog.csdn.net/jbk3311/article/details/103886095
?「(2)分步編譯」
為了演示分步編譯,我們先把上面一次性編譯生成的動態鏈接庫文件 HelloNative.dll 給刪除掉。然后再執行如下命令:
$ gcc -c -I"C:/Program Files/Java/jdk1.8.0_181/include" -I"C:/Program Files/Java/jdk1.8.0_181/include/win32" HelloNative.c HelloNative.h結果如下:
在這里我們只需要先關注生成的 HelloNative.o 文件,然后我們執行第二步驟的命令,將該文件編譯為 dll 文件:
$ gcc -Wl,--add-stdcall-alias -shared -o HelloNative.dll HelloNative.o結果如下:
2.5 再次運行Java類
使用 2.4 中的任意一種方法生成動態鏈接庫 HelloNative.dll 文件后,我們再次使用 java 命令運行 Java 類,結果如下:
我們可以看到 Java 類已經可以成功運行了,并且我們也可以看出它運行的實際是我們使用 C 語言編寫的實現方法,它作為本地方法 native 來被 Java 代碼調用。
2.6 總結
可以將 native 方法比作 Java 程序同C程序的接口,其實現步驟:
「JNI 調用 C 流程圖」:
「參考文章」
- Java native方法:https://www.jianshu.com/p/1eb6d859175d
- Java Programming TutorialJava Native Interface (JNI):https://www3.ntu.edu.sg/home/ehchua/programming/java/JavaNativeInterface.html
- Java的native方法是什么:https://blog.csdn.net/qq_29229567/article/details/80695742?utm_medium=distribute.pc_aggpage_search_result.none-task-blog-2~all~first_rank_v2~rank_v25-4-80695742.nonecase
我是阿數,葛立恒數的數,我們下期再見。
「分享、點贊、在看」
總結
以上是生活随笔為你收集整理的c调用其他类的方法_Java 的 Native 方法——今天又进步了的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 数字图像处理技术详解程序_安装地暖施工程
- 下一篇: webstorm前端调用后端接口_一篇前