Javaのネイティブメソッドインターフェース(JNI)をC/C++で実装する (3) 詳細な例(C++言語版)

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

おすすめ

転載: blog.csdn.net/O_1CxH/article/details/125587804