Use C/C++ to implement Java's Native method interface (JNI) (2) 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 elaborates on the inner 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 exports two functions, which correspond to the native methods defined in java before.

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

Write pers_h01c_jni_helloJni_impl.c (file path $ProjectDir/jni/pers_h01c_jni_helloJni_impl.c), including the implementation of the export method in .h

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

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

The include files required for compilation include pers_h01c_jni_helloJni.h under jni/, jni.h under $JAVA_HOME/include, and jni_md.h under $JAVA_HOME/include/darwin (the reason for darwin here is that the experimental environment is the MacOS operating system , the names of other systems are different, for example, Windows may be win32)

MacOS (darwin) compilation command

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

Note that the output file name must start with lib, which is stipulated by JNI, and the file format is dylib.

The compilation command of Windows is slightly different. On the one hand, the dynamiclib option is changed. On the other hand, the output file does not need to start with lib, and the format is 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

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 3: Detailed explanation of examples (C++ language version)

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

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