JNI プログラミング (C/C++)
記事ディレクトリ
セクション 1: クイック スタート
プロセスをすばやく実行するための簡単なデモ詳細については、「C/C++ を使用して Java のネイティブ メソッド インターフェイス (JNI) を実装する (1) クイック スタート」を参照してください。
セクション 2: 詳細な例 (C 言語版)
このセクションでは、セクション 1 (C) の内部の例について詳しく説明します。
Java の javah ツールを使用して .h を生成します
生成された .h ファイル (パスは $ProjectDir/jni/pers_h01c_jni_helloJni.h) は次のとおりです。
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class pers_h01c_jni_helloJni */
#ifndef _Included_pers_h01c_jni_helloJni
#define _Included_pers_h01c_jni_helloJni
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: pers_h01c_jni_helloJni
* Method: helloWorld
* Signature: (Ljava/lang/String;)V
*/
JNIEXPORT void JNICALL Java_pers_h01c_jni_helloJni_helloWorld
(JNIEnv *, jobject, jstring);
/*
* Class: pers_h01c_jni_helloJni
* Method: staticHelloWorld
* Signature: (Ljava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_pers_h01c_jni_helloJni_staticHelloWorld
(JNIEnv *, jclass, jstring);
#ifdef __cplusplus
}
#endif
#endif
.h が 2 つの関数をエクスポートしていることがわかります。これらの関数は、以前に Java で定義されたネイティブ メソッドに対応しています。
JNIEXPORT void JNICALL Java_pers_h01c_jni_helloJni_helloWorld
(JNIEnv *, jobject, jstring);
- pers.h01c.jni.helloWorld の helloWorld メソッドに対応
- タイプ JNIEnv * のポインターは、Jni の環境オブジェクトを指します
- jobject 型のパラメータは、 java のpers.h01c.jni.helloWorldオブジェクト(クラスのインスタンス)に対応します。
- jstring型で渡されたパラメータの型(helloWorld(String inputArg))
JNIEXPORT jstring JNICALL Java_pers_h01c_jni_helloJni_staticHelloWorld
(JNIEnv *, jclass, jstring);
- pers.h01c.jni.helloWorld の staticHelloWorld メソッドに対応
- JNIEnv * および jstring 同上
- ここでの 2 番目のパラメーターは、pers.h01c.jni.helloWorldクラスに対応する jclass 型になります。これは、クラスでのみ操作できる静的メソッド (静的) であるためです。
生成された .h に従って、対応する C 実装を記述します。
エクスポート メソッドの実装を .h に含めて、pers_h01c_jni_helloJni_impl.c (ファイル パス $ProjectDir/jni/pers_h01c_jni_helloJni_impl.c) を記述します。
#include <stdio.h>
#include "pers_h01c_jni_helloJni.h" // 需要引入之前的.h文件
JNIEXPORT void JNICALL Java_pers_h01c_jni_helloJni_helloWorld (JNIEnv * env, jobject obj, jstring str){
const char * name = (*env) -> GetStringUTFChars(env, str, NULL); // 读取传入的UTF-编码字符串
printf("hello %s", name);
(*env) -> ReleaseStringUTFChars(env, str, name); // 释放字符串对应的内存
};
JNIEXPORT jstring JNICALL Java_pers_h01c_jni_helloJni_staticHelloWorld (JNIEnv * env, jclass cls, jstring str){
const char * name = (*env) -> GetStringUTFChars(env, str, NULL);
jstring ret = (*env) -> NewStringUTF(env, name); // 创建新的java string
return ret;
}
envの使い方の違いについての説明
JniEnv ポインタは JVM 仮想マシンの環境を指します C 言語にはオブジェクトの概念がないため、次のメソッドを使用して env メソッドを呼び出す必要があります
(*env) -> GetStringUTFChars(env, str, NULL);
C++にはオブジェクトの概念があるのでそのまま使えます
env->GetStringUTFChars(jstr, nullptr);
C ダイナミック リンク ライブラリにコンパイル
コンパイルに必要なインクルード ファイルには、jni/ の下の pers_h01c_jni_helloJni.h、$JAVA_HOME/include の下の jni.h、および $JAVA_HOME/include/darwin の下の jni_md.h が含まれます (ここで darwin を使用する理由は、実験環境が MacOS オペレーティング システムであるためです)。 、他のシステムの名前は異なります。たとえば、Windows は win32 の可能性があります)。
MacOS (darwin) コンパイル コマンド
export JNI_LIB_NAME=helloJni
gcc -dynamiclib -I $JAVA_HOME/include -I $JAVA_HOME/include/darwin -shared -o lib/lib$JNI_LIB_NAME.dylib jni/pers_h01c_jni_helloJni_impl.c
出力ファイル名はJNIで規定されているlibで始まる必要があり、ファイル形式はdylibであることに注意してください。
Windows のコンパイル コマンドは少し異なり、dynamiclib オプションが変更されている一方で、出力ファイルは lib で始まる必要はなく、フォーマットは dll です。
gcc -Wl,--add-stdcall-alias -I"$JAVA_HOME$\include" -I"$JAVA_HOME$\include\win32" -shared -o ./lib/$JNI_LIB_NAME$.dll ./jni/pers_h01c_jni_helloJni_impl.c
Java コードを変更してテストする
最初のステップで作成した Java クラスにダイナミック リンク ライブラリを静的にインポートします. ライブラリ名は上記の JNI_LIB_NAME と同じです.
ここでは C 言語版を例に取ります.C++ 版のプロセスも同じです.
// file location: $ProjectDir/src/pers/h01c/jni/helloJni.java
package pers.h01c.jni;
public class helloJni {
static {
System.loadLibrary("helloJni"); // 注意这个库必须要在java.library.path里
}
public native void helloWorld(String inputArg);
public native static String staticHelloWorld(String inputArg);
}
ライブラリが見つからないというエラーが報告された場合は、コマンド ラインの実行時に VM オプションを追加する必要があります。
- Djava.library.path=$ProjectDir/lib/
Intelj IDE 環境の場合、$ProjectDir の場所は、Intelj の組み込みマクロ: $ProjectFileDir$である必要があります。
- Djava.library.path=$ProjectFileDir$/lib/
セクション 3: 例の詳細な説明 (C++ 言語版)
このセクションでは、セクション 1 (C++) の内部例の詳細な説明に焦点を当てます. 詳細については、「C/C++ を使用して Java のネイティブ メソッド インターフェイス (JNI) を実装する (3) 詳細な例 (C++ 言語版)」を参照してください。
セクション 4: JNI データ型
このセクションでは、JNI で定義されているいくつかのデータ型を紹介します. 詳細については、「C/C++ を使用して Java のネイティブ メソッド インターフェイス (JNI) を実装する (4) JNI データ型」を参照してください。
セクション 5: jstring クラスや jobject クラスなどのオブジェクト データのメソッド
このセクションでは、JNI で最も一般的に使用される jstring (java.lang.String) と jobject (Object) の操作メソッドについて詳しく説明します. 詳細については、「C /C++ を使用して Java のネイティブ メソッド インターフェイス (JNI) を実装する (5) jstring」を参照してください。 class などのオブジェクトデータの class および jobject メソッド
セクション 6: さまざまな JNI データ型のコード例
このセクションでは、前のセクション 1 ~ 5 を組み合わせて、複数のデータ型を含むサンプル JNI-C++ コードを記述します. 詳細については、「C/C++ を使用して Java のネイティブ メソッド インターフェイス (JNI) を実装する (6) 複数の JNI データ型コードの例」を参照してください
付録: コード
プロジェクト全体のリソース パッケージ リンク: JNI_C/C++_Demo