機械翻訳について

第1章: 入門

この章では、Java Native Interface (JNI)を紹介します。 JNIは、ネイティブ・プログラミング・インタフェースです。 これによって、Java仮想マシン(VM)で実行されるJavaコードがC、C++、アセンブリ言語などほかのプログラミング言語で書かれたアプリケーションやライブラリと相互運用できるようになります。

JNIのもっとも重要な利点は、これがベースとなるJava VMの実装に何の制限も課さないということです。 そのため、Java VMベンダーはVMのほかの部分に影響を与えずに、JNIのサポートを追加できます。 プログラマは、1つのバージョンのネイティブ・アプリケーションまたはライブラリを記述すれば、それがJNIをサポートするすべてのJava VM上で動作することを期待できます。

この章では次のトピックについて説明します。

Java Native Interfaceの概要

Javaでアプリケーション全体を記述できる一方で、Javaだけではアプリケーションのニーズを満たせない状況もあります。 Javaでアプリケーション全体を記述できない場合、プログラマはJNIを使用してJavaネイティブ・メソッドを記述することにより、このような状況に対処できます。

次に、Javaネイティブ・メソッドを使用する必要のある場合をいくつか示します。

JNIを介して、プログラミングにネイティブ・メソッドを使用することにより、次のことが可能になります。

また、呼び出しAPIとともにJNIを使用することにより、任意のネイティブ・アプリケーションによるJava VMの埋込みが可能になります。 これにより、プログラマはVMソース・コードにリンクしなくても、既存のアプリケーションをJava対応にできます。

これまでの経緯

異なるベンダーのVMは異なるネイティブ・メソッド・インタフェースを提供します。 これらの異なるインタフェースによって、プログラマは与えられたプラットフォームで複数バージョンのネイティブ・メソッド・ライブラリを生成、維持、配布することが必要になります。

代表的なネイティブ・メソッド・インタフェースを次に紹介します。

JDK 1.0ネイティブ・メソッド・インタフェース

JDK 1.0は、ネイティブ・メソッド・インタフェースを添付して出荷されました。 残念ながら、2つの大きな理由のため、このインタフェースはほかのJava VMには適用できませんでした。

第一に、ネイティブ・コードはJavaオブジェクトのフィールドにC構造体のメンバーとしてアクセスしました。 ただし、Java言語仕様では、オブジェクトをメモリーにどのように配置するかを定義していません。 VMがオブジェクトをメモリーに異なったやり方で配置する場合、プログラマはネイティブ・メソッド・ライブラリを再コンパイルする必要があります。

第二に、JDK 1.0のネイティブ・メソッド・インタフェースは古典的なガベージ・コレクタに依存していました。 たとえば、unhandマクロを無制限に使用すると、ネイティブ・スタックの古典的な走査が必要になりました。

Java Runtime Interface

Netscapeは、Java仮想マシンで提供されるサービスの一般的なインタフェースであるJava Runtime Interface (JRI)を提案しました。 JRIは移植性を考慮して設計されましたが、基盤となるJava VMの実装の詳細について十分に考慮されていません。 JRIはネイティブ・メソッド、デバッグ、リフレクション、埋め込み(呼び出し)など、広範囲にサポートしていました。

Raw Native InterfaceおよびJava/COMインタフェース

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ライセンス保持者の間で一連の検討を行いました。 それにより、標準のネイティブ・メソッド・インタフェースは、次の要件を満たす必要があることが明らかになりました。

Java Native Interfaceのアプローチ

既存のアプローチの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のプログラミングを行なってください。 JNIのプログラミングは、エンド・ユーザーが実行している可能性のあるベンダーのVMなど未知のものから隔離してくれます。 JNI標準に準拠することで、ネイティブ・ライブラリに対して、特定のJava VMで実行できる可能性が高くなります。

Java VMを実装する場合には、JNIも実装する必要があります。 JNIは長年にわたり、オブジェクト表現やガベージ・コレクション・スキームなど、VM実装に対するオーバーヘッドや制限を課さないように努力しています。 当社が見落とした問題を発見した場合は、ご連絡下さい。