JNI プログラミング (C/C++)
記事ディレクトリ
セクション 1: クイック スタート
プロセスをすばやく実行するための簡単なデモ詳細については、「C/C++ を使用して Java のネイティブ メソッド インターフェイス (JNI) を実装する (1) クイック スタート」を参照してください。
セクション 2: 詳細な例 (C 言語版)
このセクションでは、セクション 1 の内部例の詳細な説明 (C) を提供します。詳細については、「C/C++ を使用して Java のネイティブ メソッド インターフェイス (JNI) を実装する (2) 例の詳細な説明 (C 言語版)」を参照してください。
セクション 3: 例の詳細な説明 (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++ 実装を記述します。
C++には文字列ライブラリがあり、文字列のサポートが優れているため、最初にjstringとc++の文字列変換の処理関数を記述できます
std::string jstring2string(JNIEnv*env, jstring jstr)
{
const char* tmpStr = env->GetStringUTFChars(jstr, nullptr);
std::string ret(tmpStr);
env->ReleaseStringUTFChars(jstr, tmpStr);
return ret;
}
jstring string2jstring(JNIEnv* env, std::string str)
{
return env->NewStringUTF(str.c_str());
}
c++ 文字列クラスのインターフェイスのサポートにより、文字列、特に UTF 文字列を C 文字配列よりも簡単に操作できます。
#include <iostream>
#include <string>
#include "pers_h01c_jni_helloJni.h"
using namespace std;
std::string jstring2string(JNIEnv*env, jstring jstr) {
// 省略,见上方代码}
jstring string2jstring(JNIEnv* env, std::string str) {
// 省略,见上方代码}
JNIEXPORT void JNICALL Java_pers_h01c_jni_helloJni_helloWorld (JNIEnv * env, jobject jobj, jstring str){
const string &s = jstring2string(env, str);
string cstring0 = "jni-cpp:" + s;
cout << cstring0 << endl;
}
JNIEXPORT jstring JNICALL Java_pers_h01c_jni_helloJni_staticHelloWorld(JNIEnv * env, jclass jcls, jstring str){
const string &s = jstring2string(env, str);
string cstring0 = "input_string=" + s;
return string2jstring(env, cstring0);
}
envの使い方の違いについての説明
JniEnv ポインタは JVM 仮想マシンの環境を指します C 言語にはオブジェクトの概念がないため、次のメソッドを使用して env メソッドを呼び出す必要があります
(*env) -> GetStringUTFChars(env, str, NULL);
C++にはオブジェクトの概念があるのでそのまま使えます
env->GetStringUTFChars(jstr, nullptr);
C++ ダイナミック リンク ライブラリにコンパイルする
gcc は C++ 言語しかコンパイルできず、リンクできないため、g++ でコンパイルする必要があります. コンパイル コマンドでは、gcc を g++ に置き換えるだけです。
MacOS でコンパイルする
export JNI_LIB_NAME=helloJniCpp
g++ -dynamiclib -I $JAVA_HOME/include -I $JAVA_HOME/include/darwin -shared -o lib/lib$JNI_LIB_NAME.dylib jni/pers_h01c_jni_helloJni_impl.cpp
さらに、C/C++ コードは cmake などのツールでコンパイルすることもでき、コードの C/C++ 部分は CLion IDE を使用して記述できます。
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/
セクション 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