1 - はじめに
この章では、Java ネイティブインタフェース (JNI) を紹介します。JNI は、ネイティブプログラミングインタフェースです。これによって、Java Virtual Machine (VM)で実行される Java コードが C、C++、アセンブリ言語など他のプログラミング言語で書かれたアプリケーションやライブラリと相互運用できるようになります。
JNI の最も重要な利点は、これが基礎となる Java VM の実装に何の制限も課さないということです。そのため、Java VM ベンダは VM の他の部分に影響を与えずに、JNI のサポートを追加できます。プログラマは、ネイティブアプリケーションまたはライブラリの 1 つのバージョンを書き、これが JNI をサポートするすべての Java VM と動作することを期待できます。
この章では次の説明項目を扱います
Java ネイティブインタフェースの概要
Java でアプリケーション全体を書くことができる一方、Java だけでアプリケーションのニーズを満たせない状況もあります。Java でアプリケーション全体を書くことができないとき、こうした状況を処理するためにプログラマは JNI を使用し、Java ネイティブメソッドを書きます。
次の例は Java ネイティブメソッドを使用する必要のある場合です。
- 標準 Java クラスライブラリが、アプリケーションが必要とするプラットフォーム依存機能をサポートしない。
- 既に他の言語で書かれたライブラリを持っており、それに JNI を経由して Java コードからアクセスしたいと希望している。
- 一部のタイムクリティカルなコードをアセンブリなどの低レベル言語で実装することを望む。
JNI のプログラミングによって、次のことを行うネイティブメソッドを使用することができます。
- Java オブジェクトを生成、検査、更新する(配列と文字列を含む)。
- Java メソッドを呼び出す。
- 例外をキャッチしスローする。
- クラスをロードし、クラス情報を得る。
- 実行時の型チェックを実行する。
また、任意のネイティブアプリケーションが Java VM を埋め込むことができるようにするには、 呼び出し APIと共に JNI を使用します。これによって、プログラマは VM ソースコードにリンクせずに簡単に、既存のアプリケーションを Java 使用可能にできます。
背景
現在、異なるベンダの VM は異なるネイティブメソッドインタフェースを提供します。これらの異なるインタフェースによって、プログラマは与えられたプラットフォームで複数バージョンのネイティブメソッドライブラリを生成、維持、配布することが必要になります。
既存の代表的なネイティブメソッドインタフェースを以下に紹介します。
- JDK 1.0 ネイティブメソッドインタフェース
- Netscape の Java ランタイムインタフェース
- Microsoft の ローネイティブインタフェースおよび Java/COM インタフェース
JDK 1.0 ネイティブメソッドインタフェース
JDK 1.0 は、ネイティブメソッドインタフェースを添付して出荷されました。残念ながら、2つ
の大きな理由のため、このインタフェースは他の Java VM への適用には適しません。
第 1 にネイティブコードは、Java オブジェクトのフィールドに C 構造体のメンバとしてアクセスします。しかしJava 言語仕様は、オブジェクトをメモリにどのように配置するかを定義していません。VM がオブジェクトをメモリに異なって配置する場合、プログラマはネイティブメソッドライブラリを再コンパイルする必要があります。
第 2 に、JDK 1.0 のネイティブメソッドインタフェースは厳格なガベージコレクタに
依存しています。例えば、制限のない unhand マクロの使用によってネイティブスタックを慎重に調べる必要がでてきます。
Java ランタイムインタフェース
Netscape は Java virtual machine で提供されるサービスの一般的なインタフェースで
ある、Java ランタイムインタフェース(JRI)を提案しました。JRI は移植性を念頭に設計されています---これは基礎となる Java VM の実装の詳細についてわずかしか考慮していません。JRI はネイティブメソッド、デバッギング、リフレクション、埋め込み(呼び出し)などを含めて、広範囲をサポートしています。
ローネイティブインタフェース および Java/COM インタフェース
Microsoft Java VM は、2 つのネイティブメソッドインタフェースをサポートします。低レベルでは、効率的なローネイティブインタフェース(RNI)を提供します。 JDK のネイティブメソッドインタフェースとのソースレベルの高度の後方互換性を提供しますが、 RNI には大きな違いが 1 つあります。厳格なガベージコレクションに依存する代わりに、ネイティブコードは RNI 機能を使用し明示的にガベージコレクタと相互動作しなければなりません。
高レベルでは、Microsoft の Java/COM インタフェースは Java VM に対して言語独立の標準バイナリインタフェースを提供します。Java コードは COM オブジェクトをあたかも Java オブジェクトであるかのように使用できます。Java クラスもまた COM クラスとしてシステムの残りに開示することができます。
目的
充分検討された統一標準インタフェースは誰にも次のような利点を提供するはずです。
- 各 VM ベンダはネイティブコードのより大きな本体をサポートできる。
- ツールビルダは、異なる種類のネイティブメソッドインタフェースを維持する必要はない。
- アプリケーションプログラマは、ネイティブコードの 1 つのバージョンを書くことができ、このバージョンは異なる VM 上で動作する。
標準のネイティブメソッドインタフェースを達成する最善の方法は、Java VM に関心の
あるすべての関係者を取り込むことです。このため、統一されたネイティブメソッドインタフェースの設計について Java ライセンシーの間で一連の検討を行いました。標準のネイティブメソッドインタフェースは、次の要件を満たす必要があることが検討から明らかになりました。
- バイナリ互換 - 主要な目標は、与えられたプラットフォーム上のすべての Java VM 実装全体でのネイティブメソッドライブラリのバイナリ互換です。
- 効率 - タイムクリティカルコードをサポートするためには、ネイティブメソッドインタフェースはわずかのオーバーヘッドしか課してはなりません。VM 独立(およびバイナリ互換)を保証する既知の技術のすべては、ある量のオーバーヘッドをもたらします。効率と VM 独立の間にある程度の譲歩をする必要があります。
- 機能性 - インタフェースはネイティブメソッドが有用なタスクを達成できるようにするために、充分に Java VM の内部を開示する必要があります。
Java ネイティブインタフェースのアプローチ
既存のアプローチの1つを標準インタフェースとして適用することを望んでいました。そ
れは、異なる VM の複数のインタフェースを学ぶ必要があるプログラマにかける負荷を最低限にするはずだからです。あいにく、既存の解決策ではこの目標を完全に満足に達成するものは存在しませんでした。
Netscape の JRI は、移植性のあるネイティブメソッドインタフェースとして想定するものに一番近いものであり、設計の際の開始点としてこれを使用しました。JRI に慣れ親しんだ読者は、API 名前付け規則、メソッドとフィールド ID の使用、ローカルとグローバル参照の使用などの類似性に気付くでしょう。しかし最善の努力に関らず、VM は JRI および JNI の両方をサポートできますが、JNI は JRI とバイナリ互換ではありません。
Microsoft の RNI は、厳格でないガベージコレクタに取り組むネイティブメソッドの問
題を解決しているため、JDK 1.0 を超えた改善といえます。しかし、RNI は VM 独立ネイティブメソッドインタフェースとしては適当ではありません。JDK のように、RNI ネイティブメソッドは Java オブジェクトに C 構造体としてアクセスします。このため次の 2 つの問題が発生します。
- RNI は、内部 Java オブジェクトの配置をネイティブコードに開示する。
- C 構造体として Java オブジェクトに直接アクセスすることによって、高度のガベージコレクションアルゴリズムで必要な「書き込みバリヤ」を効率的に取り込むことができなくなる。
バイナリ標準として、COM は異なる VM を超えて完全なバイナリ互換を保証します。COM メソッドの起動には間接的な呼び出しだけが必要で、この呼び出しはほとんどオーバーヘッドを伴いません。さらに、COM オブジェクトはバージョンの問題を解決するダイナミックリンクライブラリに大きな改善をもたらします。
しかし、標準 Java ネイティブメソッドインタフェースとしての COM の使用は、次のい
くつかの要因によって妨げられます
- 第 1 に、Java/COM インタフェースは private フィールドへのアクセスや一般的な例外の発生などの要求される特定の機能を欠いています。
- 第 2 に、Java/COM インタフェースは自動的に Java オブジェクトに対して標準の IUnknown および IDispatch COM インタフェースを提供し、ネイティブコードが public メソッドとフィールドをアクセスできるようにします。あいにく、IDispatch インタフェースはオーバーロードの Java メソッドを扱わず、メソッド名の照合では大文字小文字を区別します。さらに、IDispatch インタフェースを経由して開示されるすべての Java メソッドは、ダイナミック型チェックと型変換を実行するためにラップされます。これは、IDispatch インタフェースが型チェックがない言語(Basic など)を念頭に設計されているからです。
- 第 3 に、個別の低レベル関数を扱う代わりに、COM はソフトウェアコンポーネント(独立したアプリケーションを含む)が一緒に動作するように設計されています。すべての Java クラスまたは低レベルネイティブメソッドをソフトウェアコンポーネントとして扱うことが適当でないと考えます。
- 第 4 に、COM の即座の適用は UNIX プラットフォーム上でサポートを欠いているため妨げられます。
Java オブジェクトを COM オブジェクトとしてネイティブコードに開示はしませんが、JNI インタフェース自身は COM とバイナリ互換です。COM が使用するものと同じジャンプテーブル構造体と呼び出し規則を使用します。これは、COM のクロスプラットフォームサポートが使用可能になると直ちに、JNI は Java VM の COM インタフェースになれることを意味します。
JNI が、与えられた Java VM がサポートする唯一のネイティブメソッドインタフェース
であるべきだとは考えません。標準インタフェースは、ネイティブコードライブラリを異なる Java VM にロードしたいプログラマを支援します。あるケースでは、最高の効率を達成するために、プログラマは低レベルな VM 固有インタフェースを使用する必要があります。他のケースでは、プログラマは高レベルインタフェースを使用し、ソフトウェアコンポーネントを構築するかもしれません。実際、Java 環境とコンポーネントソフトウェア技術が円熟してくるにつれて、ネイティブメソッドはその重要性を徐々に失うことを望んでいます。
JNI のプログラミング
ネイティブメソッドプログラマは、JNI のプログラミングを開始する必要があります。JNI のプログラミングは、エンドユーザが実行している可能性のあるベンダの VM など未知のものから隔離してくれます。JNI 標準に準拠することで、ネイティブライブラリに対して、与えられたJava VM で実行する最善の機会を与えます。例えば、JDK 1.1 は JDK 1.0 で実装された古い型のネイティブメソッドインタフェースのサポートを継続しますが、JDK の将来バージョンは古い型のネイティブメソッドインタフェースのサポートを止めることは確かです。古い型のインタフェースに依存するネイティブメソッドは書き直す必要があるでしょう。
Java VM を実装する場合には、JNI も実装する必要があります。Javasoft およびライセ
ンシーは、JNI がオブジェクト表現、ガベージコレクション方式などを含め、VM 実装にオーバーヘッドや制限を課さないように最善の努力をしています。我々が見落とした問題に遭遇した場合には、ご連絡ください。
目次 | 前項目 | 次項目
Java ネイティブインタフェース仕様 (1997年3月15日にdkramer によって生成されたHTML)
Copyright (C) 1996, 1997 Sun Microsystems, Inc.All rights reserved
コメントは、jni@java.sun.com宛てに送ってください。