「Java Native Interface」の版間の差分

削除された内容 追加された内容
Javaden (会話 | 投稿記録)
m fix typo
en:Java Native Interface#How the JNI works (01:46, 21 July 2009 UTC) を粗訳、「JNIの動作」節として追加。外部リンク節追加。
8行目:
 
このJNIは[[Eclipse (統合開発環境)|Eclipse]]で用いられている[[Standard Widget Toolkit|SWT]]にも使われている。
 
==JNIの動作==
 
JNIフレームワークでは、ネイティブ関数は.cもしくは.cppファイルに分離して実装する。C++はJNIに対して多少洗練されたインターフェイスを提供する。JVMは''<code>JNIEnv</code>''ポインタ、''<code>jobject</code>''ポインタ、そしてJavaメソッドで定義されたすべてのJava引数を通して、ネイティブな関数を起動する。JNI関数は以下のような形式となる。
 
<syntaxhighlight lang="c">
JNIEXPORT void JNICALL Java_ClassName_MethodName
(JNIEnv *env, jobject obj)
{
/*ネイティブコードをここに記述する*/
}
</syntaxhighlight>
 
''<code>env<code>''ポインタはJVNへのインタフェースを含む構造体である。これはJVMとの相互作用および、Javaオブジェクトとの連携に必要な全ての関数を含んでいる。JNI関数の例としては、ネイティブ配列とJava配列の相互変換、ネイティブ文字列とJava文字列の相互変換、オブジェクトのインスタンス化、例外の送出などが挙げられる。基本的には、Javaコードでできることは全て<code>JNIEnv</code>を用いて行うことができる。以下の例示ではJava文字列をネイティブな文字列に変換する。
 
<syntaxhighlight lang="cpp">
//C++ code
JNIEXPORT void JNICALL Java_ClassName_MethodName
(JNIEnv *env, jobject obj, jstring javaString)
{
//Java文字列よりネイティブ文字列を取得する
const char *nativeString = env->GetStringUTFChars(javaString, 0);
 
//ネイティブ文字列に関する処理
 
//この行を忘れてはいけない!
env->ReleaseStringUTFChars(javaString, nativeString);
}
</syntaxhighlight>
 
<syntaxhighlight lang="c">
/*C code*/
JNIEXPORT void JNICALL Java_ClassName_MethodName
(JNIEnv *env, jobject obj, jstring javaString)
{
/*Java文字列よりネイティブ文字列を取得する*/
const char *nativeString = (*env)->GetStringUTFChars(env, javaString, 0);
 
/*ネイティブ文字列に関する処理*/
 
/*この行を忘れてはいけない!*/
(*env)->ReleaseStringUTFChars(env, javaString, nativeString);
}
</syntaxhighlight>
 
C++ではJavaのように、オブジェクトのメソッドという概念を持つため、C++のJNIコードはCのそれに比べて文法的に多少クリアである。
Cでは<code>env</code>パラメータは<code>(*env)-></code>で被参照され、<code>env</code>
はオブジェクトメソッド起動セマンティクスの一部として、明示的に<code>JNIEnv</code>メソッドに渡されなければならない。
C++では<code>env</code>パラメータは<code>env-></code>で被参照される。<code>env</code>パラメータはオブジェクトメソッド起動セマンティクスの一部として暗黙的に渡される。
 
ネイティブ変数型とJava変数型はそれぞれ相互変換をすることができる。オブジェクトや配列、文字列などの合成型のために、ネイティブコードは<code>JNIEnv</code>のメソッド呼び出しにおいて、明示的なデータの変換を行う必要がある。
 
===変数型のマッピング===
 
以下の表ではJavaとネイティブ間の変数型のマッピングを示す。
 
{| class="wikitable"
!ネイティブ変数型
!Java変数型
!Description
!Type signature
|-
|unsigned char
|jboolean
|unsigned 8 bits
|Z
|-
|signed char
|jbyte
|signed 8 bits
|B
|-
|unsigned short
|jchar
|unsigned 16 bits
|C
|-
|short
|jshort
|signed 16 bits
|S
|-
|int
|jint
|signed 32 bits
|I
|-
|
long long<br/>__int64
|jlong
|signed 64 bits
|J
|-
|float
|jfloat
|32 bits
|F
|-
|double
|jdouble
|64 bits
|D
|}
 
"L fully-qualified-class"という記述はクラスが名前によって一意に識別できることを示す。
例えば"Ljava/lang/String"はjava.lang.Stringを参照する。また、冒頭の<code>[></code>はその型の配列を意味する。例えば、<code>[I</code>はint型の配列である。
 
これらの型は交換可能である。開発者は型キャスト無しで、<code>int</code>型と同様に<code>jint</code>を使用することができる。<code>jint</code>型から<code>int<code>型への変換も同様である。
 
しかしながら、文字列や配列のJava-ネイティブ間のマッピングについては様相が異なる。もし、あなたが<code>char *</code>のあるべき場所に<code>jstring</code>を使用した場合、そのコードはJVMをクラッシュさせるだろう。
 
<syntaxhighlight lang="cpp">
// !!! 誤ったコード !!! //
JNIEXPORT void JNICALL Java_ClassName_MethodName
(JNIEnv *env, jobject obj, jstring javaString)
{
printf("%s", javaString);
}
</syntaxhighlight>
 
<syntaxhighlight lang="cpp">
// 正しいコード //
JNIEXPORT void JNICALL Java_ClassName_MethodName
(JNIEnv *env, jobject obj, jstring javaString)
{
//Get the native string from javaString
const char *nativeString = env->GetStringUTFChars(javaString, 0);
printf("%s", nativeString);
//DON'T FORGET THIS LINE!!!
env->ReleaseStringUTFChars(javaString, nativeString);
}
</syntaxhighlight>
 
 
このことはJava配列についても同様である。配列の全ての要素の合計を得る例を用いて以下に示す。
 
<syntaxhighlight lang="cpp">
// !!! 誤ったコード !!! //
JNIEXPORT jint JNICALL
Java_IntArray_sumArray(JNIEnv *env, jobject obj, jintArray arr)
{
int i, sum = 0;
for (i = 0; i < 10; i++) {
sum += arr[i];
}
return sum;
}
</syntaxhighlight>
 
<syntaxhighlight lang="cpp">
// 正しいコード //
JNIEXPORT jint JNICALL
Java_IntArray_sumArray(JNIEnv *env, jobject obj, jintArray arr)
{
jint buf[10];
jint i, sum = 0;
env->GetIntArrayRegion(arr, 0, 10, buf);
for (i = 0; i < 10; i++) {
sum += buf[i];
}
return sum;
}
</syntaxhighlight>
 
=== JNIEnv* ===
 
JNIEnv引数は呼び出しの間のみ有効となる。呼び出しの外で引数を使う為には、以下のようにAttachCurrentThreadとDetachCurrentThreadを使用する必要がある。
 
JNIEnv *env;
(*g_vm)->AttachCurrentThread (g_vm, (void **) &env, NULL);
// do stuff
(*g_vm)->DetachCurrentThread (g_vm);
 
 
 
{{Computer-stub}}
18 ⟶ 192行目:
*[[SWIG]]: 多言語に対応したインターフェイス生成ツールで、C/C++のライブラリ用の JNI コードを生成する
 
==外部リンク==
*[http://java.sun.com/docs/books/jni/ Java Native Interface: Programmer's Guide and Specification]
*[http://java.sun.com/javase/6/docs/technotes/guides/jni/index.html Sun's JNI page, including the JNI Specification]
*[http://www.ibm.com/developerworks/java/library/j-jni/index.html Best practices for using the Java Native Interface]
*[http://gcc.gnu.org/onlinedocs/gcj/About-CNI.html GNU CNI Tutorial]
*[http://www.codeproject.com/java/jnibasics1.asp A JNI Tutorial at CodeProject.com (Microsoft specific)]
*[http://www.codetoad.com/java_simpleJNI.asp JNI Tutorial at CodeToad.com]
*[http://java.sun.com/developer/onlineTraining/Programming/JDCBook/jniexamp.html Larger JNI example from Sun]
*[http://developer.apple.com/java/jniuniversal.html JNI in XCode from Apple]
 
[[Category:Javaプラットフォーム]]