C コードは、次のようなもので生成できる関数宣言を使用しています。
javah -classpath apps/samples/hello-jni/project/src com.example.hellojni.HelloJni
javah
HelloJni.java からコンパイルされたバイトコード ファイル (HelloJni.class) を処理して、で宣言されたメソッドnative
を C 関数プロトタイプに抽出します。実装では、次のいずれかを定義しています。
jstring Java_com_example_hellojni_HelloJni_stringFromJNI(JNIEnv*, jobject);
おそらく、最初に関数を宣言したり、によって生成されたヘッダーを使用したりすることなく、これを行っていjavah
ます。Cでは、それは一般的に許可されています。おそらく彼らは の出力をコピー、貼り付け、編集したのでしょjavah
うjavah
。
更新:
また、C では、関数宣言に名前付きパラメーターは必要ありません。実装では、使用される各パラメーターに名前を付ける必要があります。したがって、次のことが可能です。
Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env, jobject thiz )
{
// implementation
}
または、2 番目の引数が実装で使用されていないため:
Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env, jobject )
{
// implementation
}
リンキング
一部の Java コードが を呼び出すと、動的リンクが発生しますsystem.loadLibrary("name")
。native
このような呼び出しの一般的な場所は、ライブラリによって実装されるメソッドを宣言する各クラスの静的初期化子ブロックです。
public class HelloJni
{
static { system.loadLibrary("hellojni"); }
...
}
次に、JVM はプロパティの検索パスで共有ライブラリ (.so または .dll) を検索しますjava.library.path
。プラットフォームに依存するさまざまなプレフィックス (「lib」) とサフィックス (「.so」、「.dll」) を試して、ファイルを見つけます。そのようなファイルが見つからない場合は、例外がスローされます。
独立して、 で宣言された関数が呼び出されるとnative
、JVM はロードされたライブラリを検索して、関数の名前と一致するエクスポートされた関数を探します。マッチングは、C コンパイラ/リンカーで使用される JNI 関数の命名規則javah
および C 関数マングリング規則に従って行われます。そのような関数が見つからない場合は、例外がスローされます。jni.h と によって生成されたヘッダーを含めると、すべてうまくいくはずですjavah
。
注: には十分注意してくださいNewStringUTF
。これは、UTF-8 エンコーディングを変更した 0 で終わる Unicode 文字列を取ります。この例は、文字列で使用される文字の限定されたサブセット、ソース ファイルのエンコーディング、および文字列の変更された UTF-8 エンコーディングと同一のバイト シーケンスを偶然作成するリテラルからのコンパイラによる char 配列の構築に依存しています。
C の代わりに C++11 を使用できる場合、保持している UTF-16 コード単位NewString
で非常にうまく機能します。std::u16string
(UTF-16 コード単位は、Java が内部で使用するものです。)