Use C/C++ to implement Java's Native method interface (JNI) (5) Methods of object data such as jstring class and jobject class

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 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 (Obejct) in JNI

jstring type related methods

// 普通字符串方法
jstring (JNICALL *NewString) (JNIEnv *env, const jchar *unicode, jsize len);
jsize (JNICALL *GetStringLength) (JNIEnv *env, jstring str);
const jchar *(JNICALL *GetStringChars) (JNIEnv *env, jstring str, jboolean *isCopy);
void (JNICALL *ReleaseStringChars) (JNIEnv *env, jstring str, const jchar *chars);
// UTF字符串方法,一般选用这种
jstring (JNICALL *NewStringUTF) (JNIEnv *env, const char *utf);
jsize (JNICALL *GetStringUTFLength) (JNIEnv *env, jstring str);
const char* (JNICALL *GetStringUTFChars) (JNIEnv *env, jstring str, jboolean *isCopy);
void (JNICALL *ReleaseStringUTFChars) (JNIEnv *env, jstring str, const char* chars);

The following mainly describes the methods related to UTF strings:

  • NewStringUTF Input environment and char* string of C, create a java.lang.String object in JVM, if successful, return jstring object reference, otherwise return NULL
  • GetStringUTFLength input environment and jstring object reference, get the length of this java.lang.String
  • GetStringUTFChars input environment and jstring object reference, convert it to C char* string, the isCopy parameter represents whether to return the copy value (when isCopy is true, it means return a copy of the JVM internal source string, and for the newly generated String allocates memory space; when isCopy is false, the pointer to the source string inside the JVM will be returned, no new string object will be generated, and the modification will be done directly on the original string, but this is not recommended because The strings in the string pool in the Java mechanism cannot be changed; in addition, JNI has JNI_TRUE and JNI_FALSE for initializing jboolean, and isCopy can pass in jboolean references)
  • ReleaseStringUTFChars notifies the JVM that the memory of the string in the input parameter is no longer used, and the parameter corresponds to the input char* and output jstring of calling the GetStringUTFChars method

Note that each GetStringUTFChars must have a corresponding ReleaseStringUTFChars for memory recovery.

Note 2, the above enumeration shows the calling method of C, and the method with the same name in C++ does not have the first env parameter (because it is called directly through the object method). The enumerations in this section and the next section are all C methods, but the last C++ implementation used in code examples.

Jobject type related methods

FindClass

Enter the name of a class and return the jclass pointer corresponding to the class; use "/" to replace the "." in java for the name of the class

jclass (JNICALL *FindClass) (JNIEnv *env, const char *name);
// example: 
// jclass array_list_class = env->FindClass("java/lang/Math");

GetObjectClass

Enter a jobject and get its type

jclass (JNICALL *GetObjectClass) (JNIEnv *env, jobject obj);
// example:
// jclass input_class = env->GetObjectClass(input_obj);

Get{/Static}FieldID

Obtain the ID number of the object field/obtain the static field of the class, and this ID number is used for subsequent Get/Set field operations

jfieldID (JNICALL *GetFieldID) 
(JNIEnv *env, jclass clazz, const char *name, const char *sig);
// example:
// jfieldID amount_field = env->GetFieldID(input_class, "amount", "I"); 

jfieldID (JNICALL *GetStaticFieldID)
(JNIEnv *env, jclass clazz, const char *name, const char *sig);
// example:
// jfieldID static_str_field = env->GetStaticFieldID(input_class, "staticString", "Ljava/lang/String;"); 

Note that the incoming parameters include not only the class jclass, variable name, but also a type signature. This type signature is used to describe the type of the variable. The type signature comparison table is as follows:

Field Type Signature
boolean Z
byte B
char C
shot S
int I
long J
float F
double D
void V
Object The letter L is followed by the full class name separated by "/" plus the character ";", for example "Ljava/lang/String;"
Array The character [ followed by other types of signatures, such as "[I", "[Ljava/lang/String;"

Get{/Static}{FIELDTYPE}Field

// {FIELDTYPE}代表字段数据类型

// Get{FIELDTYPE}Field系列的函数输入都是jobect和fieldID(使用GetFieldID函数得到的字段ID)
// 返回该对象的对应字段值

jobject GetObjectField(jobject obj, jfieldID fieldID);
jboolean GetBooleanField(jobject obj, jfieldID fieldID);
jbyte GetByteField(jobject obj, jfieldID fieldID);
jchar GetCharField(jobject obj, jfieldID fieldID);
jshort GetShortField(jobject obj, jfieldID fieldID);
jint GetIntField(jobject obj, jfieldID fieldID);
jlong GetLongField(jobject obj, jfieldID fieldID);
jfloat GetFloatField(jobject obj, jfieldID fieldID);
jdouble GetDoubleField(jobject obj, jfieldID fieldID);

// GetStatic{FIELDTYPE}Field系列的函数输入都是jclass和fieldID(使用GetStaticFieldID函数得到的字段ID)
// 由于是获取的类的静态字段,所以输入是jclass而不是jobject
// 返回该类的静态字段值

jobject GetStaticObjectField(jclass clazz, jfieldID fieldID);
jboolean GetStaticBooleanField(jclass clazz, jfieldID fieldID);
jbyte GetStaticByteField(jclass clazz, jfieldID fieldID);
jchar GetStaticCharField(jclass clazz, jfieldID fieldID);
jshort GetStaticShortField(jclass clazz, jfieldID fieldID);
jint GetStaticIntField(jclass clazz, jfieldID fieldID);
jlong GetStaticLongField(jclass clazz, jfieldID fieldID);
jfloat GetStaticFloatField(jclass clazz, jfieldID fieldID);
jdouble GetStaticDoubleField(jclass clazz, jfieldID fieldID);

Set{/Static}{FIELDTYPE}Field

// Set{FIELDTYPE}Field系列的函数输入都是jobect、fieldID(使用GetFieldID函数得到的字段ID)和赋予的新值
    void (JNICALL *SetObjectField)
      (JNIEnv *env, jobject obj, jfieldID fieldID, jobject val);
    void (JNICALL *SetBooleanField)
      (JNIEnv *env, jobject obj, jfieldID fieldID, jboolean val);
    void (JNICALL *SetByteField)
      (JNIEnv *env, jobject obj, jfieldID fieldID, jbyte val);
    void (JNICALL *SetCharField)
      (JNIEnv *env, jobject obj, jfieldID fieldID, jchar val);
    void (JNICALL *SetShortField)
      (JNIEnv *env, jobject obj, jfieldID fieldID, jshort val);
    void (JNICALL *SetIntField)
      (JNIEnv *env, jobject obj, jfieldID fieldID, jint val);
    void (JNICALL *SetLongField)
      (JNIEnv *env, jobject obj, jfieldID fieldID, jlong val);
    void (JNICALL *SetFloatField)
      (JNIEnv *env, jobject obj, jfieldID fieldID, jfloat val);
    void (JNICALL *SetDoubleField)
      (JNIEnv *env, jobject obj, jfieldID fieldID, jdouble val);

// SetStatic{FIELDTYPE}Field系列的函数输入都是jclass、fieldID(使用GetStaticFieldID函数得到的字段ID)和赋予的新值
// 由于是set的是类的静态字段,所以输入是jclass而不是jobject
    void (JNICALL *SetStaticObjectField)
      (JNIEnv *env, jclass clazz, jfieldID fieldID, jobject value);
    void (JNICALL *SetStaticBooleanField)
      (JNIEnv *env, jclass clazz, jfieldID fieldID, jboolean value);
    void (JNICALL *SetStaticByteField)
      (JNIEnv *env, jclass clazz, jfieldID fieldID, jbyte value);
    void (JNICALL *SetStaticCharField)
      (JNIEnv *env, jclass clazz, jfieldID fieldID, jchar value);
    void (JNICALL *SetStaticShortField)
      (JNIEnv *env, jclass clazz, jfieldID fieldID, jshort value);
    void (JNICALL *SetStaticIntField)
      (JNIEnv *env, jclass clazz, jfieldID fieldID, jint value);
    void (JNICALL *SetStaticLongField)
      (JNIEnv *env, jclass clazz, jfieldID fieldID, jlong value);
    void (JNICALL *SetStaticFloatField)
      (JNIEnv *env, jclass clazz, jfieldID fieldID, jfloat value);
    void (JNICALL *SetStaticDoubleField)
      (JNIEnv *env, jclass clazz, jfieldID fieldID, jdouble value);

Get{/Static}MethodID

Obtain the ID number of the object method/class static method, which is used for subsequent Call operations

jmethodID GetMethodID(jclass clazz, const char *name, const char *sig);
// example:
// jmethodID object_method = env->GetMethodID(input_class, "someMethod", "(Ljava/lang/String;IZD)V")

jmethodID GetStaticMethodID(jclass clazz, const char *name, const char *sig);
// example:
// jmethodID static_class_method = env->GetMethodID(input_class, "someStaticMethod", "(IFJ)V")

The input parameters are jclass, method name and method signature; the signature of the method contains the data type of its input and output

方法签名格式:"(输入类型签名列表)输出类型签名"

// examples:

"()V"
// 代表是一个无参、返回为void的函数

"(ZSIJ)F"
// 代表输入参数有四个,类型依次为(boolean, short, int, long),输出参数类型为float


"(Ljava/util/ArrayList;II)Ljava/lang/String;"
// 代表输入参数有三个,类型依次为(ArraList, int, int),输出参数类型为String
// 注意L+包名后的分号";"一定要带上

General member method names are literal method names, and the initialization function is fixed as"<init>"

Call{/Static}{RETTYPE}Method{/V/A}

// {RETTYPE}部分和之前的{FIELDTYPE}同样地,可以使用数据类型进行替换,此处的{RETTYPE}类型代表函数的返回类型
// {/V/A}代表函数的输入参数类型,不写代表直接正常传入"..."可变参数,V代表va_list,A代表const jvalue *

// 此处以{RETTYPE}=Object为例,列举Call{/Static}Void{/V/A}的6个方法
jobject (JNICALL *CallObjectMethod) (JNIEnv *env, jobject obj, jmethodID methodID, ...);
jobject (JNICALL *CallObjectMethodV) (JNIEnv *env, jobject obj, jmethodID methodID, va_list args);
jobject (JNICALL *CallObjectMethodA) (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue * args);
jobject (JNICALL *CallStaticObjectMethod) (JNIEnv *env, jclass clazz, jmethodID methodID, ...);
jobject (JNICALL *CallStaticObjectMethodV) (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args);
jobject (JNICALL *CallStaticObjectMethodA) (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args);

Section 6: Code examples for various JNI data types

This section combines 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/125587999