Utiliser C/C++ pour implémenter l'interface de méthode native (JNI) de Java (5) Méthodes de données d'objet telles que la classe jstring et la classe jobject

Programmation JNI (C/C++)

Section 1 : Démarrage rapide

Une démonstration simple pour parcourir rapidement le processus. Pour plus de détails, voir Utilisation de C/C++ pour implémenter l'interface de méthode native (JNI) de Java (1) Démarrage rapide

Section 2 : Exemples détaillés (version langage C)

Cette section fournit une description détaillée (C) des exemples internes de la section 1. Pour plus de détails, voir Utilisation de C/C++ pour implémenter l'interface de méthode native (JNI) de Java (2) Exemple d'explication détaillée (version en langage C)

Section 3 : Explication détaillée des exemples (version langage C++)

Cette section se concentre sur la description détaillée des exemples internes de la section 1 (C++). Pour plus de détails, consultez Utilisation de C/C++ pour implémenter l'interface de méthode native (JNI) de Java (3) Exemple détaillé (version langage C++)

Section 4 : Types de données JNI

Cette section présente certains types de données définis dans JNI. Pour plus de détails, consultez Utilisation de C/C++ pour implémenter l'interface de méthode native de Java (JNI) (4) Types de données JNI

Section 5 : Méthodes de données d'objet telles que la classe jstring et la classe jobject

Cette section décrit en détail les méthodes de fonctionnement des jstring (java.lang.String) et jobject (Obejct) les plus couramment utilisés dans JNI

méthodes liées au type 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);

Ce qui suit décrit principalement les méthodes liées aux chaînes UTF :

  • NewStringUTF Environnement d'entrée et chaîne char* de C, créer un objet java.lang.String dans JVM, en cas de succès, renvoyer la référence de l'objet jstring, sinon renvoyer NULL
  • Environnement d'entrée GetStringUTFLength et référence d'objet jstring, obtenez la longueur de ce java.lang.String
  • Environnement d'entrée GetStringUTFChars et référence d'objet jstring, convertissez-le en chaîne C char *, le paramètre isCopy indique s'il faut renvoyer la valeur de copie (lorsque isCopy est vrai, cela signifie renvoyer une copie de la chaîne source interne JVM, et pour la chaîne nouvellement générée alloue de l'espace mémoire ; lorsque isCopy est faux, le pointeur vers la chaîne source à l'intérieur de la JVM sera renvoyé, aucun nouvel objet chaîne ne sera généré et la modification sera effectuée directement sur la chaîne d'origine, mais ce n'est pas recommandé car les chaînes dans le pool de chaînes du mécanisme Java ne peut pas être modifié ; de plus, JNI a JNI_TRUE et JNI_FALSE pour initialiser jboolean, et isCopy peut transmettre des références jboolean)
  • ReleaseStringUTFChars informe la JVM que la mémoire de la chaîne dans le paramètre d'entrée n'est plus utilisée, et le paramètre correspond à l'entrée char* et à la sortie jstring d'appeler la méthode GetStringUTFChars

Notez que chaque GetStringUTFChars doit avoir un ReleaseStringUTFChars correspondant pour la récupération de mémoire.

Remarque 2, l'énumération ci-dessus montre la méthode d'appel de C, et la méthode portant le même nom en C++ n'a pas le premier paramètre env (car elle est appelée directement via la méthode objet). sont toutes des méthodes C, mais la dernière implémentation C++ utilisée dans les exemples de code.

Méthodes liées au type Jobject

FindClass

Entrer le nom d'une classe et retourner le pointeur jclass correspondant à la classe ; utiliser "/" pour remplacer le "." en java pour le nom de la classe

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

GetObjectClass

Entrez un jobject et obtenez son type

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

Obtenir{/Static}FieldID

Obtenir le numéro d'identification du champ objet/obtenir le champ statique de la classe, et ce numéro d'identification est utilisé pour les opérations de champ Get/Set ultérieures

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

Notez que les paramètres entrants incluent non seulement la classe jclass, le nom de la variable, mais également une signature de type. Cette signature de type est utilisée pour décrire le type de la variable. Le tableau de comparaison des signatures de type est le suivant :

Type de champ Signature
booléen Z
octet B
carboniser C
tir S
entier je
long J
flotter F
double D
annuler V
Objet La lettre L est suivie du nom complet de la classe séparé par "/" plus le caractère ";", par exemple "Ljava/lang/String;"
Déployer Le caractère [ suivi d'autres types de signatures, tels que "[I", "[Ljava/lang/String ;"

Obtenir le champ {/statique}{FIELDTYPE}

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

Définir le champ {/statique}{FIELDTYPE}

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

Obtenir{/Static}MethodID

Obtenir le numéro d'identification de la méthode d'objet/méthode statique de classe, qui est utilisé pour les opérations d'appel suivantes

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

Les paramètres d'entrée sont jclass, le nom de la méthode et la signature de la méthode ; la signature de la méthode contient le type de données de son entrée et de sa sortie

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

// examples:

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

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


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

Les noms de méthode de membre généraux sont des noms de méthode littéraux, et la fonction d'initialisation est fixée comme"<init>"

Call{/Static}{RETTYPE}Méthode{/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 : Exemples de code pour différents types de données JNI

Cette section combine les sections précédentes 1 à 5 pour écrire un exemple de code JNI-C++ qui contient plusieurs types de données. Pour plus de détails, consultez Utilisation de C/C++ pour implémenter l'interface de méthode native (JNI) de Java (6) Exemple de codes de type de données JNI multiples

Annexe : Code

Lien de package de ressources pour l'ensemble du projet : JNI_C/C++_Demo

Je suppose que tu aimes

Origine blog.csdn.net/O_1CxH/article/details/125587999
conseillé
Classement