Interface)JavaからC言語/C++の関数を呼ぶ・あるいは逆にC/C++からJavaのメソッドを呼ぶための仕組み。C言語またはC++で作ったライブラリを、Windowsの場合はDLLファイル、UNIXの場合は共有オブジェクト(so)ファイルにしておき、Javaから呼び出すことが出来る。C言語/C++で作ったソースの中からJavaオブジェクトのメソッドを呼び出すことが出来る。呼び出し方はJavaとC/C++(ネイティブ)とで整合性をとる必要があり、それがJNIである。全体の手順JNIでライブラリを作るには、以下のような手順で作業する。呼び出す側のプログラム(とりあえずは宣言だけでよい)をJavaで書く。Javaのソースをコンパイルしてclassファイルを生成する。C言語/C++のヘッダーファイルを生成する。生成したヘッダーファイルの実装をC言語/C++で書く。→実装方法C言語/C++のソースをコンパイルしてDLL(SO)ファイルを生成する。JNI用ヘッダーファイルを探しに行く場所の指定が必要。→VC++の場合、ビルドしたDLLをEclipseのワークスペースに自動コピーするよう設定すると便利JavaでDLL(SO)ファイルを呼び出して実行する。ある程度の生成作業は、makefileにしたりbuild.xmlにしたりして自動化できる。宣言の作成まず、Javaでライブラリの関数を宣言する。nativeというキーワードを付け、関数本体を書かない。src);}このファイルをコンパイルし、JniJikken.classを生成しておく。→メソッド本体の例ヘッダーファイルの作成javahというコマンド(javacやjavaと同じディレクトリに入っている)を使って、C言語/C++のヘッダーファイルを生成する。この生成には、nativeを宣言したJavaのクラスファイルを入力として使う。JniJikkenこの例では、classesディレクトリ直下にあるJniJikken.classを元に、VC++のJniJikkenというディレクトリの下にJniJikken.hを生成する。宣言が新しくなっていない限りヘッダーファイルを更新しない。CヘッダーとスタブファイルジェネレータEclipseを使っている場合は(そうでない場合でも)、Ant用のbuild.xmlやバッチファイルを作っておけば便利だろう。クラスがパッケージ内に存在する場合は、以下の様にパッケージを指定する。jp.hishidama.jni.JniJikken生成されるヘッダーファイルの名前はパッケージを含んだ形になる。「jp_hishidama_jni_JniJikken.h」となる。くどいよね...(生成される場所はあくまで指定したディレクトリ直下であり、パッケージ構成のディレクトリが作られるわけではない。生成したヘッダーファイルは、以下の様になっている。__cplusplus}#endif#endifJniJikken.javaで「copy」という名前で宣言したメソッドが、「Java_JniJikken_copy」という関数になっている。この関数をC言語あるいはC++で実装してやることになる。Javaでのbyte[]やStringは、jbyteArray・jstringといった型(実体は構造体のポインター)で表現される。これらはjni.h(及びその中でincludeしているjni_md.h)で定義されている。/*ひとまずコンパイルを通す為、意味のあることは書かない*/}関数定義はヘッダーファイルから持ってきて、変数を追加すればいいだろう。最初の変数は皆envにしているようだ。2つ目の引数は、Javaから呼び出した際のクラスのインスタンス(を表すもの)が入ってくる。したがって名前をthisとするのが雰囲気的にはいいのだが、C++ではthisがキーワードとして使われているので、別のものにしなければならない。単純にobjとしている人も多いようだが、自分はthisjにしておく。(VBでthisに相当するものがMeだからmeでいいかと思ったけど、統一の為)なお、staticメソッドの場合は、jobjectでなくjclassになる。[2007-09-15]3つ目以降の引数はJava側で定義したものなので、基本的にそちらの変数と同じ名前でいいだろう。実際に使う場合にはC言語の変数を作ってやることが多いので、Javaの引数であるということを明示する為に、自分は末尾に「j」を付けている。(srcの場合はsrcj)(変数の先頭に付けないのは、そうするとJNIのクラス(jstringとか)と紛らわしいから)実際の関数の中の書き方は後述。C言語/C++のコンパイル出来上がったC言語/C++のソースをコンパイルして、DLL(Windowsの場合)やSO(UNIXの場合)を生成する。その中でincludeしているjni_md.hがある場所をコンパイラーに指示してやる必要がある。コンパイラーは「-I」オプションでインクルードパスを指定できる。機種依存部分の定義jni.hからincludeされている。$<↑この例の場合、javaのコンパイル・javahでの生成まで含んでいる。VC++の例:インクルードパスの追加方法参照。Files\Java\jdk1.6.0\include\win32Javaから実行DLL又はSOファイルを作ったら、Javaから呼び出してやる。最初に呼んでやる必要がある。この引数には、DLLやSOファイル名の中核部分を指定する。(JniJikken.dll/libJniJikken.so)最初に一度だけ確実に実行する仕組みとして、staticブロック(静的初期化子)で呼ぶ人も多い。{〜}}このloadLibraryを実行し忘れると、nativeメソッド(この例ではcopy)の実行時に以下のような例外が発生する。"main"そして、loadLibraryで指定されたDLLやSOファイルをjavaが実行時に探す為には、環境変数を設定しておく必要がある。Windowsの場合、環境変数PATHにDLLファイルのパスが入っていなければならない。Eclipseの場合はアプリケーション毎にPATHを指定できる。UNIXの場合は、環境変数LD_LIBRARY_PATHにSOファイルのパスが入っていなければならない。環境変数を設定しない場合は、実行時引数を以下の様に設定してやる。指定されたDLLやSOファイルが見つからないと、以下のような例外が発生する。"main"System.loadLibrary("Jni_Jikken");「java.library.path」が、環境変数PATHやLD_LIBRARY_PATHを意味している。(実際、Windowsの場合、System.getProperty("java.library.path")で取って来られる内容は、環境変数PATHの内容だ。)この例では、Windowsの場合DLLファイルの「Jni_Jikken.dll」が、UNIXの場合SOファイルの「libJni_Jikken.so」が見つからない。JNIエラーへ行くメールの送信先:ひしだま。