Use C/C++ to implement Java's Native method interface (JNI) (3) Detailed example (C++ language version)

JNI programming (C/C++)

Section 1: Quick Start

A simple demo to quickly run through the process. For details, see Using C/C++ to Implement Java's Native Method Interface (JNI) (1) Quick Start

Section 2: Detailed Example (C language version)

This section provides a detailed description (C) of the internal examples in Section 1. For details, see Using C/C++ to Implement Java's Native Method Interface (JNI) (2) Example Detailed Explanation (C Language Version)

Section 3: Detailed explanation of examples (C++ language version)

This section details the examples in Section 1 (C++)

Generate .h using Java's javah tool

The generated .h file (the path is $ProjectDir/jni/pers_h01c_jni_helloJni.h) is as follows

/* 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

You can see that the .h exported two functions, which corresponded one-to-one with the native methods previously defined in java.

JNIEXPORT void JNICALL Java_pers_h01c_jni_helloJni_helloWorld
  (JNIEnv *, jobject, jstring);
  • Corresponds to the helloWorld method in pers.h01c.jni.helloWorld
  • A pointer of type JNIEnv * points to the environment object of Jni
  • The parameter of jobject type corresponds to a pers.h01c.jni.helloWorld object (instance of the class) in java
  • The type of parameter passed in by jstring type (helloWorld(String inputArg))
JNIEXPORT jstring JNICALL Java_pers_h01c_jni_helloJni_staticHelloWorld
  (JNIEnv *, jclass, jstring);
  • Corresponds to the staticHelloWorld method in pers.h01c.jni.helloWorld
  • JNIEnv * and jstring ditto
  • The second parameter here becomes the jclass type, which corresponds to the pers.h01c.jni.helloWorld class , because this is a static method (static) that can only operate on the class

Write the corresponding C++ implementation according to the generated .h

C++ has a string library, so the support for strings is better, so you can first write the processing function for jstring and c++ string conversion

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());
}

With the support of the interface of the c++ string class, strings can be manipulated more conveniently than C character arrays, especially UTF strings:

#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);
}

Instructions on the difference in the use of env

The JniEnv pointer points to the environment in the JVM virtual machine. Since the C language does not have the concept of an object, you need to use the following method to call the env method

(*env) -> GetStringUTFChars(env, str, NULL);

In C++, there is an object concept, so you can use it directly

env->GetStringUTFChars(jstr, nullptr);

Compile to C++ dynamic link library

Since gcc can only compile the C++ language but cannot link it, it needs to be compiled with g++. In the compilation command, just replace gcc with g++.

Compile under 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  

In addition, the C/C++ code can also be compiled with tools such as cmake, and the C/C++ part of the code can be written using CLion IDE.

Modify the Java code and test

Statically import the dynamic link library into the java class written in the first step. The library name is the same as the JNI_LIB_NAME above.
Here, the C language version is taken as an example, and the process of the C++ version is the same.

// 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);

}

If the error that the library cannot be found is reported, you need to add VM option when running the command line:

- Djava.library.path=$ProjectDir/lib/

If it is in the Intellj IDE environment, the location of $ProjectDir should be Intellj's built-in macro: $ProjectFileDir$

- Djava.library.path=$ProjectFileDir$/lib/

Section 4: JNI Data Types

This section introduces some of the data types defined in JNI. For details, see Using C/C++ to Implement Java's Native Method Interface (JNI) (4) JNI Data Types

Section 5: Methods of object data such as jstring class and jobject class

This section describes in detail the operation methods of the most commonly used jstring (java.lang.String) and jobject (Object) in JNI. For details, see Using C/C++ to implement Java's Native method interface (JNI) (5) jstring class and jobject methods of object data such as class

Section 6: Code examples for various JNI data types

This section combines the content of the previous sections 1-5 to write an example JNI-C++ code that contains multiple data types. For details, see Using C/C++ to Implement Java's Native Method Interface (JNI) (6) Multiple JNI Data Type Codes example

Appendix: Code

Resource packaging link for the entire project: JNI_C/C++_Demo

Guess you like

Origin blog.csdn.net/O_1CxH/article/details/125587804