Use C/C++ para implementar la interfaz de método nativo (JNI) de Java (5) Métodos de datos de objetos como la clase jstring y la clase jobject

Programación JNI (C/C++)

Sección 1: Inicio rápido

Una demostración simple para ejecutar rápidamente el proceso Para obtener más información, consulte Uso de C/C++ para implementar la interfaz de método nativo (JNI) de Java (1) Inicio rápido

Sección 2: Ejemplos detallados (versión en lenguaje C)

Esta sección proporciona una descripción detallada (C) de los ejemplos internos en la Sección 1. Para obtener detalles, consulte Uso de C/C++ para implementar la interfaz de método nativo (JNI) de Java (2) Ejemplo de explicación detallada (versión del lenguaje C)

Sección 3: Explicación detallada de ejemplos (versión en lenguaje C++)

Esta sección se centra en la descripción detallada de los ejemplos internos en la Sección 1 (C++).Para obtener más información, consulte Uso de C/C++ para implementar la interfaz de método nativo (JNI) de Java (3) Ejemplo detallado (versión del lenguaje C++)

Sección 4: Tipos de datos JNI

En esta sección se presentan algunos tipos de datos definidos en JNI.Para obtener más información, consulte Uso de C/C++ para implementar la interfaz de método nativo (JNI) de Java (4) Tipos de datos de JNI

Sección 5: Métodos de datos de objetos como la clase jstring y la clase jobject

Esta sección describe en detalle los métodos de operación de jstring (java.lang.String) y jobject (Obejct) más utilizados en JNI

métodos relacionados con el tipo jstring

// 普通字符串方法
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);

A continuación se describen principalmente los métodos relacionados con cadenas UTF:

  • NewStringUTF Entorno de entrada y cadena char* de C, cree un objeto java.lang.String en JVM, si tiene éxito, devuelva la referencia del objeto jstring, de lo contrario, devuelva NULL
  • GetStringUTFLength entorno de entrada y referencia de objeto jstring, obtenga la longitud de este java.lang.String
  • GetStringUTFChars entorno de entrada y referencia de objeto jstring, conviértalo en una cadena C char*, el parámetro isCopy representa si devolver el valor de copia (cuando isCopy es verdadero, significa devolver una copia de la cadena de origen interna de JVM, y para la cadena recién generada asigna espacio de memoria; cuando isCopy es falso, se devolverá el puntero a la cadena de origen dentro de la JVM, no se generará ningún objeto de cadena nuevo y la modificación se realizará directamente en la cadena original, pero esto no se recomienda porque las cadenas en el conjunto de cadenas en el mecanismo de Java no se puede cambiar; además, JNI tiene JNI_TRUE y JNI_FALSE para inicializar jboolean, e isCopy puede pasar referencias jboolean)
  • ReleaseStringUTFChars notifica a la JVM que la memoria de la cadena en el parámetro de entrada ya no se usa, y el parámetro corresponde al carácter de entrada* y la cadena de salida de llamar al método GetStringUTFChars

Tenga en cuenta que cada GetStringUTFChars debe tener un ReleaseStringUTFChars correspondiente para la recuperación de la memoria.

Nota 2, la enumeración anterior muestra el método de llamada de C, y el método con el mismo nombre en C++ no tiene el primer parámetro env (porque se llama directamente a través del método de objeto). Las enumeraciones en esta sección y la siguiente sección son todos métodos de C, pero la última implementación de C++ utilizada en ejemplos de código.

Métodos relacionados con el tipo Jobject

Buscarclase

Ingrese el nombre de una clase y devuelva el puntero jclass correspondiente a la clase; use "/" para reemplazar el "." en java para el nombre de la clase

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

ObtenerClaseObjeto

Ingrese un proyecto de trabajo y obtenga su tipo

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

Obtener{/Static}FieldID

Obtener el número de ID del campo de objeto/obtener el campo estático de la clase, y este número de ID se usa para operaciones de campo Get/Set subsiguientes

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

Tenga en cuenta que los parámetros entrantes incluyen no solo la clase jclass, el nombre de la variable, sino también una firma de tipo. Esta firma de tipo se utiliza para describir el tipo de la variable. La tabla de comparación de firmas de tipo es la siguiente:

Tipo de campo Firma
booleano Z
byte B
carbonizarse C
disparo S
En t I
largo j
flotar F
doble D
vacío V
Objeto La letra L va seguida del nombre completo de la clase separado por "/" más el carácter ";", por ejemplo "Ljava/lang/String;"
Formación El carácter [ seguido de otros tipos de firmas, como "[I", "[Ljava/lang/String;"

Obtener{/Static}{FIELDTYPE}Campo

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

Establecer{/Estático}{FIELDTYPE}Campo

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

Obtener{/Static}MethodID

Obtenga el número de ID del método de objeto/método estático de clase, que se utiliza para operaciones de llamada posteriores

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")

Los parámetros de entrada son jclass, nombre del método y firma del método; la firma del método contiene el tipo de datos de su entrada y salida

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

// examples:

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

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


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

Los nombres de métodos de miembros generales son nombres de métodos literales, y la función de inicialización se fija como"<init>"

Llamada{/Estático}{RETTYPE}Método{/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);

Sección 6: Ejemplos de código para varios tipos de datos JNI

Esta sección combina las secciones anteriores 1 a 5 para escribir un ejemplo de código JNI-C++ que contiene varios tipos de datos. Para obtener más información, consulte Uso de C/C++ para implementar la interfaz de método nativo (JNI) de Java (6) Ejemplo de códigos de tipos de datos JNI múltiples

Apéndice: Código

Enlace de empaquetado de recursos para todo el proyecto: JNI_C/C++_Demo

Supongo que te gusta

Origin blog.csdn.net/O_1CxH/article/details/125587999
Recomendado
Clasificación