Android JNI 學習(一):JNI 簡介
JNI 即 Java Native Interface 是 native 編程接口,它允許在Java虛擬機(VM)內運行Java代碼與其他編程語言(主要是C和C++)編寫的應用程序和庫進行交互操作。
JNI最重要的好處是它對底層Java VM的實現沒有任何限制。因此,Java VM供應商可以添加對JNI的支持,而不會影響VM的其他部分。程序員可以編寫一個native應用程序或庫的版本,並期望它可以與支持JNI的所有Java VM一起使用。
本文主要將從以下幾點講述JNI相關的內容,用於我們了解JNI:
概述、背景、目標、實現方式。
一、JNI 概述
雖然您可以完全使用Java編寫應用程序,但有些情況下Java本身並不能滿足您的應用程序的需求。
以下示例說明何時需要使用Java Native方法:
- 標準Java類庫不支持應用程序所需的與平臺相關的功能。
- 您已經有一個使用另一種語言編寫的庫,並希望通過JNI使其可以訪問Java代碼。
- 您希望在較低級別的語言(如C/C++)中實現一小部分時間關鍵代碼。
通過JNI編程,您可以使用Native方法:
- 創建,檢查和更新Java對象(包括數組和字符串)。
- 調用Java方法。
- 捕獲並拋出異常。
- 加載類並獲取類信息。
- 執行運行時類型檢查。
二、JNI 產生的歷史背景
來自不同供應商的VM提供了不同的Native方法接口。這些不同的接口迫使程序員在給定平臺上生成,維護和分發多個版本的本機方法庫。
我們簡要介紹一些本機方法接口,例如:
- JDK 1.0本機方法接口
- Netscape的Java運行時接口
- Microsoft的原始本機接口和Java / COM接口
1、JDK 1.0本機方法接口
JDK 1.0 附帶了Native方法接口。不幸的是,這個接口不適合其他Java VM采用有兩個主要原因。
首先,本機代碼訪問Java對象中的字段作為C結構的成員。但是,Java語言規範沒有定義對象在內存中的布局方式。
其次,JDK 1.0的本機方法接口依賴於保守的垃圾收集器。unhand
例如,不受限制地使用宏使得必須保守地掃描本機堆棧。
2、Java運行時接口
Netscape提出了Java運行時接口(JRI),它是Java虛擬機中提供的服務的通用接口。JRI的設計考慮了可移植性 - 它對底層Java VM中的實現細節做了很少的假設。JRI解決了廣泛的問題,包括本機方法,調試,反射,嵌入(調用)等。
3、原始本機接口和Java / COM接口
Microsoft Java VM支持兩種本機方法接口。在低級別,它提供了有效的原始本機接口(RNI)。RNI提供了與JDK本機方法接口的高度源級向後兼容性,盡管它有一個主要區別。本機代碼必須使用RNI函數與垃圾收集器明確交互,而不是依賴於保守的垃圾收集。
在更高級別,Microsoft的Java / COM接口為Java VM提供了與語言無關的標準二進制接口。Java代碼可以像使用Java對象一樣使用COM對象。Java類也可以作為COM類公開給系統的其余部分。
三、JNI 產生的目標
我們相信,統一且經過深思熟慮的標準接口為每個人提供以下好處:
- 每個VM供應商都可以支持更多的natvie代碼。
- 工具構建器不必維護不同類型的natvie方法接口。
- 應用程序編程人員將能夠編寫其natvie代碼的一個版本,該版本將在不同的VM上運行。
實現標準本機方法接口的最佳方法是讓所有各方都參與Java VM。因此,我們在Java許可證持有者之間組織了一系列關於統一本機方法接口設計的討論。從討論中可以清楚地看出,標準本機方法接口必須滿足以下要求:
- 二進制兼容性 - 主要目標是在給定平臺上的所有Java VM實現中對本機方法庫進行二進制兼容。程序員應該只為給定平臺維護其本機方法庫的一個版本。
- 效率 - 為了支持時間關鍵代碼,本機方法接口必須施加很少的開銷。確保VM獨立性(以及二進制兼容性)的所有已知技術都帶有一定量的開銷。我們必須以某種方式在效率和VM獨立性之間達成妥協。
- 功能 - 接口必須公開足夠的Java VM內部,以允許本機方法完成有用的任務。
四、實現JNI的方式討論
我們希望采用現有方式之一作為標準,主要是為了給在不同VM中學習多個接口的程序員帶來最小的負擔。但是令人失望的是,目前沒有現有的解決方案來實現我們這樣的想法。
Netscape的JRI是最接近我們想要的的便攜式Natvie方法接口,並被用作我們設計的起點。熟悉JRI的讀者會註意到API命名約定,方法和字段ID的使用,本地和全局引用的使用等方面的相似之處。盡管我們盡最大努力,但JNI與JRI不是二進制兼容的,盡管VM可以同時支持JRI和JNI。
微軟的RNI是對JDK 1.0的改進,因為它解決了使用非保守垃圾收集器的本機方法的問題。但是,RNI不適合作為獨立於VM的本機方法接口。與JDK一樣,RNI本機方法將Java對象作為C結構訪問,但也導致兩個問題:
- RNI將內部Java對象的布局暴露給本機代碼。
- 直接訪問Java對象作為C結構使得無法有效地合並“寫入障礙”,這在高級垃圾收集算法中是必需的。
作為二進制標準,COM確保跨不同VM的完全二進制兼容性。調用COM方法只需要間接調用,這幾乎不會產生任何開銷。此外,COM對象在解決版本問題方面比動態鏈接庫有了很大的改進。
但是,使用COM作為標準Java本機方法接口受到以下幾個因素的阻礙:
- 首先,Java / COM接口缺少某些所需的功能,例如訪問私有字段和引發一般異常。
- 其次,Java / COM接口自動為Java對象提供標準的IUnknown和IDispatch COM接口,以便本機代碼可以訪問公共方法和字段。遺憾的是,IDispatch接口不處理重載的Java方法,並且在匹配方法名稱時不區分大小寫。此外,通過IDispatch接口公開的所有Java方法都被包裝以執行動態類型檢查和強制。這是因為IDispatch接口在設計時考慮了弱類型語言(例如Basic)。
- 第三,COM不是處理單獨的低級功能,而是旨在允許軟件組件(包括完整的應用程序)協同工作。我們認為將所有Java類或低級本機方法視為軟件組件是不合適的。
- 第四,由於缺乏對UNIX平臺的支持,因此立即采用COM受到阻礙。
雖然Java對象不作為COM對象公開給本機代碼,但JNI接口本身與COM二進制兼容。JNI使用與COM相同的跳轉表結構和調用約定。這意味著,只要跨平臺支持COM,JNI就可以成為Java VM的COM接口。
JNI不被認為是給定Java VM支持的唯一本機方法接口。標準接口使程序員受益,他們希望將本機代碼庫加載到不同的Java VM中。在某些情況下,程序員可能必須使用較低級別的VM特定接口來實現最高效率。在其他情況下,程序員可能使用更高級別的界面來構建軟件組件。實際上,隨著Java環境和組件軟件技術的日趨成熟,本機方法將逐漸失去意義。
五、總結
首先本文是譯文,原文地址為:https://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/intro.html。
同時也是本人整理的JNI教程的第一篇,可能部分內容語法有點不通順,但是看完了也能基本了解JNI是什麽,產生的背景,以及JNI被實現的方式。
Android JNI 學習(一):JNI 簡介