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

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

おすすめ

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