1. 程式人生 > >Android JNI 學習(一):JNI 簡介

Android JNI 學習(一):JNI 簡介

將在 編程語言 ase 環境 公開 javase 全局 face let

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編寫時,程序員使用JNI編寫Java Native 方法來處理這些情況。

以下示例說明何時需要使用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語言規沒有定義對象在內存中的布局方式。

如果Java VM在內存中以不同方式布局對象,則程序員必須重新編譯本機方法庫。

其次,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 簡介