0

私はこのサンプルに少し困惑しています。ネイティブ メソッドには JNI に登録する方法が 2 つあることを知っています。静的なものを使用する場合は、* .h のような署名を生成し、それをネイティブ ファイルに含める必要があります。どうやら、hello-jni は動的なものを使用していません。コードは次のようになります。

#include <string.h>
#include <jni.h> 

/* This is a trivial JNI example where we use a native method
 * to return a new VM String. See the corresponding Java source
 * file located at:
 *
 *   apps/samples/hello-jni/project/src/com/example/hellojni/HelloJni.java
 */
jstring
Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env,
                                                  jobject thiz )
{
    return (*env)->NewStringUTF(env, "Hello from JNI !");
}

とジャバ

public native String  stringFromJNI();

Google で検索したところ、JVM に関する手がかりが見つかりました。JVM についてほとんど知りません。誰か助けてもらえますか?

4

1 に答える 1

0

C コードは、次のようなもので生成できる関数宣言を使用しています。

javah -classpath apps/samples/hello-jni/project/src com.example.hellojni.HelloJni 

javahHelloJni.java からコンパイルされたバイトコード ファイル (HelloJni.class) を処理して、で宣言されたメソッドnativeを C 関数プロトタイプに抽出します。実装では、次のいずれかを定義しています。

jstring Java_com_example_hellojni_HelloJni_stringFromJNI(JNIEnv*, jobject);

おそらく、最初に関数を宣言したり、によって生成されたヘッダーを使用したりすることなく、これを行っていjavahます。Cでは、それは一般的に許可されています。おそらく彼らは の出力をコピー、貼り付け、編集したのでしょjavahjavah

更新: また、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 が内部で使用するものです。)

于 2013-06-26T17:39:56.380 に答える