目次 | 前へ | 次へ |
この章では、Java Native Interface (JNI) を紹介します。JNI は、ネイティブプログラミングインタフェースです。これによって、Java 仮想マシン (VM) で実行される Java コードが C、C++、アセンブリ言語などほかのプログラミング言語で書かれたアプリケーションやライブラリと相互運用できるようになります。
JNI のもっとも重要な利点は、これがベースとなる Java VM の実装に何の制限も課さないということです。そのため、Java VM ベンダーは VM のほかの部分に影響を与えずに、JNI のサポートを追加できます。プログラマは、1 つのバージョンのネイティブアプリケーションまたはライブラリを記述すれば、それが JNI をサポートするすべての Java VM 上で動作することを期待できます。
この章では次のトピックについて説明します。
Java でアプリケーション全体を記述できる一方で、Java だけではアプリケーションのニーズを満たせない状況もあります。Java でアプリケーション全体を記述できない場合、プログラマは JNI を使用して Java ネイティブメソッドを記述することにより、このような状況に対処できます。
次に、Java ネイティブメソッドを使用する必要のある場合をいくつか示します。
JNI を介して、プログラミングにネイティブメソッドを使用することにより、次のことが可能になります。
また、呼び出し API とともに JNI を使用することにより、任意のネイティブアプリケーションによる Java VM の埋め込みが可能になります。これにより、プログラマは VM ソースコードにリンクしなくても、既存のアプリケーションを Java 対応にできます。
異なるベンダーの VM は異なるネイティブメソッドインタフェースを提供します。これらの異なるインタフェースによって、プログラマは与えられたプラットフォームで複数バージョンのネイティブメソッドライブラリを生成、維持、配布することが必要になります。
代表的なネイティブメソッドインタフェースを次に紹介します。
JDK 1.0 は、ネイティブメソッドインタフェースを添付して出荷されました。残念ながら、2 つの大きな理由のため、このインタフェースはほかの Java VM には適用できませんでした。
第一に、ネイティブコードは Java オブジェクトのフィールドに C 構造体のメンバーとしてアクセスしました。ただし、Java 言語仕様では、オブジェクトをメモリーにどのように配置するかを定義していません。VM がオブジェクトをメモリーに異なったやり方で配置する場合、プログラマはネイティブメソッドライブラリを再コンパイルする必要があります。
第二に、JDK 1.0 のネイティブメソッドインタフェースは古典的なガベージコレクタに依存していました。たとえば、unhand
マクロを無制限に使用すると、ネイティブスタックの古典的な走査が必要になりました。
Netscape は、Java 仮想マシンで提供されるサービスの一般的なインタフェースである Java Runtime Interface (JRI) を提案しました。JRI は移植性を考慮して設計されましたが、基盤となる Java VM の実装の詳細について十分に考慮されていません。JRI はネイティブメソッド、デバッグ、リフレクション、埋め込み (呼び出し) など、広範囲にサポートしていました。
Microsoft Java VM は、2 つのネイティブメソッドインタフェースをサポートします。低レベルでは、効率的な Raw Native Interface (RNI) を提供します。RNI は、JDK のネイティブメソッドインタフェースとのソースレベルの高度な下位互換性を提供しますが、大きな違いが 1 つあります。厳格なガベージコレクションに依存する代わりに、ネイティブコードは RNI 機能を使用しガベージコレクタと明示的に相互動作しなければなりません。
これより高位のレベルでは、Microsoft の Java/COM インタフェースは、言語に依存しない標準バイナリインタフェースを Java VM に提供します。Java コードは COM オブジェクトを Java オブジェクトであるかのように使用できます。Java クラスもまた COM クラスとしてシステムの残りに開示できます。
充分検討された標準インタフェースには、次のような利点があります。
標準のネイティブメソッドインタフェースを確立する最善の方法は、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 つの問題があります。
バイナリ標準として、COM は異なる VM 間で完全なバイナリ互換を保証します。COM メソッドの起動には間接的な呼び出しだけが必要で、この呼び出しはオーバーヘッドをほとんど伴いません。さらに、COM オブジェクトはバージョン問題の解決という点でダイナミックリンクライブラリに大きな改善をもたらします。
しかし、標準 Java ネイティブメソッドインタフェースとして COM を使用するには、次のいくつかの要因が問題になります。
Java オブジェクトを COM オブジェクトのようにネイティブコードに開示はしませんが、JNI インタフェース自身は COM とバイナリ互換です。COM が使用するものと同じジャンプテーブル構造体と呼び出し規則を使用します。これは、COM のクロスプラットフォームサポートが使用可能になると、JNI はただちに Java VM の COM インタフェースになれることを意味します。
JNI は、単に所定の Java VM によってサポートされたネイティブメソッドインタフェースであるとは考えられていません。標準インタフェースが役に立つのは、プログラマがネイティブコードライブラリを異なる Java VM にロードする場合です。あるケースでは、最高の効率を達成するために、プログラマは低レベルな VM 固有インタフェースを使用する必要があります。ほかのケースでは、プログラマは高レベルインタフェースを使用し、ソフトウェアコンポーネントを構築する可能性があります。実際、Java 環境とコンポーネントソフトウェア技術が円熟するのに伴い、ネイティブメソッドの重要性は徐々に失われていくでしょう。
ネイティブメソッドプログラマであれば、JNI のプログラミングを行なってください。JNI のプログラミングは、エンドユーザーが実行している可能性のあるベンダーの VM など未知のものから隔離してくれます。JNI 標準に準拠することで、ネイティブライブラリに対して、特定の Java VM で実行できる可能性が高くなります。
Java VM を実装する場合には、JNI も実装する必要があります。JNI は長年にわたり、オブジェクト表現やガベージコレクションスキームなど、VM 実装に対するオーバーヘッドや制限を課さないように努力しています。当社が見落とした問題を発見した場合は、ご連絡下さい。
Java SE 6.0 では、非推奨の構造体 JDK1_1InitArgs および JDK1_1AttachArgs を削除し、それに代わって JavaVMInitArgs および JavaVMAttachArgs を使用します。
目次 | 前へ | 次へ |