目次 | 前の項目 | 次の項目 Java Native Interface 仕様

はじめに


第 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 実装に対するオーバーヘッドや制限を課さないように努力しています。当社が見落とした問題を発見した場合は、ご連絡ください。

変更点

Java SE 6.0 では、推奨されなくなった構造体 JDK1_1InitArgs および JDK1_1AttachArgs を削除し、それに代わって JavaVMInitArgs および JavaVMAttachArgs を使用します。

 


目次 | 前の項目 | 次の項目