4 Säilykkeet 37111fd42c ... bcc30e9207

Tekijä SHA1 Viesti Päivämäärä
  yang yi bcc30e9207 # doc:JNI(Java Native Interface)的参数传递和返回的文档 2 viikkoa sitten
  yang yi c5b91250ac # resource:删除C代码的编译产物 2 viikkoa sitten
  yang yi 5507687b49 # config:JNI中三种引用类型的代码的编译配置 2 viikkoa sitten
  yang yi 8f5ba9d102 # feat:JNI中三种引用类型的使用 2 viikkoa sitten

+ 5 - 2
Makefile

@@ -9,7 +9,10 @@ LDFLAGS := -shared -fPIC -lc
 SOURCES := \
     c/helloWorld/JNI_Hello_World \
     c/parameter/JNI_parameter \
-    c/parameter/JNI_object_parameter
+    c/parameter/JNI_object_parameter \
+    c/reference/JNI_localReference \
+    c/reference/JNI_globalReference \
+    c/reference/JNI_weakGlobalReference \
 
 # 生成目标文件列表
 OBJECTS := $(addsuffix .o, $(SOURCES))
@@ -32,4 +35,4 @@ all: $(SHARED_LIBS)
 clean:
 	rm -f $(OBJECTS) $(SHARED_LIBS)
 
-.PHONY: all clean
+.PHONY: all clean

BIN
c/helloWorld/JNI_Hello_World.o


BIN
c/helloWorld/JNI_Hello_World.so


BIN
c/parameter/JNI_object_parameter.o


BIN
c/parameter/JNI_object_parameter.so


BIN
c/parameter/JNI_parameter.o


BIN
c/parameter/JNI_parameter.so


+ 27 - 0
c/reference/JNI_globalReference.c

@@ -0,0 +1,27 @@
+#include "space_anyi_jni_reference_GlobalReferenceTest.h"
+JNIEXPORT jlong JNICALL Java_space_anyi_jni_reference_GlobalReferenceTest_getPersonHandler(JNIEnv *env, jobject this){
+    //1.获取对应的jclass
+    jclass class_Person = (*env)->FindClass(env, "Lspace/anyi/jni/reference/Person;");
+    //2.获取对应的构造方法
+    jmethodID constructor = (*env)->GetMethodID(env, class_Person, "<init>", "(Ljava/lang/String;I)V");
+    //3.创建对象
+    jstring name = (*env)->NewStringUTF(env, "杨逸");
+    jobject person = (*env)->NewObject(env, class_Person, constructor,name,18);
+    //4.获取全局引用
+    jobject globalReference = (*env)->NewGlobalRef(env, person);
+    //5.转换为句柄,使用intptr_t类型作为中间类型,避免精度丢失
+    jlong handler = (jlong)(intptr_t)globalReference;
+    return handler;
+}
+
+JNIEXPORT jobject JNICALL Java_space_anyi_jni_reference_GlobalReferenceTest_getPerson(JNIEnv *env, jobject this, jlong handler){
+    //1.通过句柄获取全局引用,使用intptr_t类型作为中间类型
+    jobject person = (jobject)(intptr_t)handler;
+    //2.返回对象
+    return person;
+}
+
+JNIEXPORT void JNICALL Java_space_anyi_jni_reference_GlobalReferenceTest_freePerson(JNIEnv *env, jobject this, jlong handler){
+    //1.通过句柄释放全局引用的内存
+    (*env)->DeleteGlobalRef(env, (jobject)(intptr_t)handler);
+}

+ 11 - 0
c/reference/JNI_localReference.c

@@ -0,0 +1,11 @@
+#include "space_anyi_jni_reference_LocalReferenceTest.h"
+JNIEXPORT jobject JNICALL Java_space_anyi_jni_reference_LocalReferenceTest_getPerson(JNIEnv *env, jobject this){
+    //1.获取对应的jclass
+    jclass class_Person = (*env)->FindClass(env, "Lspace/anyi/jni/reference/Person;");
+    //2.获取对应的构造方法
+    jmethodID constructor = (*env)->GetMethodID(env, class_Person, "<init>", "(Ljava/lang/String;I)V");
+    //3.创建对象
+    jstring name = (*env)->NewStringUTF(env, "杨逸");
+    jobject person = (*env)->NewObject(env, class_Person, constructor,name,18);
+    return person;
+}

+ 28 - 0
c/reference/JNI_weakGlobalReference.c

@@ -0,0 +1,28 @@
+#include "space_anyi_jni_reference_WeakGlobalReferenceTest.h"
+JNIEXPORT jlong JNICALL Java_space_anyi_jni_reference_WeakGlobalReferenceTest_getPersonHandler(JNIEnv *env, jobject this){
+        //1.获取对应的jclass
+        jclass class_Person = (*env)->FindClass(env, "Lspace/anyi/jni/reference/Person;");
+        //2.获取对应的构造方法
+        jmethodID constructor = (*env)->GetMethodID(env, class_Person, "<init>", "(Ljava/lang/String;I)V");
+        //3.创建对象
+        jstring name = (*env)->NewStringUTF(env, "杨逸-弱引用");
+        jobject person = (*env)->NewObject(env, class_Person, constructor,name,18);
+        //4.获取全局弱引用
+        jobject weakGlobalReference = (*env)->NewWeakGlobalRef(env, person);
+        //5.转换为句柄,使用intptr_t类型作为中间类型,避免精度丢失
+        jlong handler = (jlong)(intptr_t)weakGlobalReference;
+        return handler;
+}
+
+JNIEXPORT jobject JNICALL Java_space_anyi_jni_reference_WeakGlobalReferenceTest_getPerson(JNIEnv *env, jobject this, jlong handler){
+    //1.通过句柄获取全局弱引用,使用intptr_t类型作为中间类型
+    jobject person = (jobject)(intptr_t)handler;
+    return person;
+}
+
+JNIEXPORT void JNICALL Java_space_anyi_jni_reference_WeakGlobalReferenceTest_freePerson(JNIEnv *env, jobject this, jlong handler){
+    //1.通过句柄获取全局弱引用,使用intptr_t类型作为中间类型
+    jobject weakGlobalReference = (jobject)(intptr_t)handler;
+    //2.释放全局弱引用
+    (*env)->DeleteWeakGlobalRef(env, weakGlobalReference);
+}

+ 37 - 0
c/reference/space_anyi_jni_reference_GlobalReferenceTest.h

@@ -0,0 +1,37 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+/* Header for class space_anyi_jni_reference_GlobalReferenceTest */
+
+#ifndef _Included_space_anyi_jni_reference_GlobalReferenceTest
+#define _Included_space_anyi_jni_reference_GlobalReferenceTest
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class:     space_anyi_jni_reference_GlobalReferenceTest
+ * Method:    getPersonHandler
+ * Signature: ()J
+ */
+JNIEXPORT jlong JNICALL Java_space_anyi_jni_reference_GlobalReferenceTest_getPersonHandler
+  (JNIEnv *, jobject);
+
+/*
+ * Class:     space_anyi_jni_reference_GlobalReferenceTest
+ * Method:    getPerson
+ * Signature: (J)Lspace/anyi/jni/reference/Person;
+ */
+JNIEXPORT jobject JNICALL Java_space_anyi_jni_reference_GlobalReferenceTest_getPerson
+  (JNIEnv *, jobject, jlong);
+
+/*
+ * Class:     space_anyi_jni_reference_GlobalReferenceTest
+ * Method:    freePerson
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL Java_space_anyi_jni_reference_GlobalReferenceTest_freePerson
+  (JNIEnv *, jobject, jlong);
+
+#ifdef __cplusplus
+}
+#endif
+#endif

+ 21 - 0
c/reference/space_anyi_jni_reference_LocalReferenceTest.h

@@ -0,0 +1,21 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+/* Header for class space_anyi_jni_reference_LocalReferenceTest */
+
+#ifndef _Included_space_anyi_jni_reference_LocalReferenceTest
+#define _Included_space_anyi_jni_reference_LocalReferenceTest
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class:     space_anyi_jni_reference_LocalReferenceTest
+ * Method:    getPerson
+ * Signature: ()Lspace/anyi/jni/reference/Person;
+ */
+JNIEXPORT jobject JNICALL Java_space_anyi_jni_reference_LocalReferenceTest_getPerson
+  (JNIEnv *, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif

+ 37 - 0
c/reference/space_anyi_jni_reference_WeakGlobalReferenceTest.h

@@ -0,0 +1,37 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+/* Header for class space_anyi_jni_reference_WeakGlobalReferenceTest */
+
+#ifndef _Included_space_anyi_jni_reference_WeakGlobalReferenceTest
+#define _Included_space_anyi_jni_reference_WeakGlobalReferenceTest
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class:     space_anyi_jni_reference_WeakGlobalReferenceTest
+ * Method:    getPersonHandler
+ * Signature: ()J
+ */
+JNIEXPORT jlong JNICALL Java_space_anyi_jni_reference_WeakGlobalReferenceTest_getPersonHandler
+  (JNIEnv *, jobject);
+
+/*
+ * Class:     space_anyi_jni_reference_WeakGlobalReferenceTest
+ * Method:    getPerson
+ * Signature: (J)Lspace/anyi/jni/reference/Person;
+ */
+JNIEXPORT jobject JNICALL Java_space_anyi_jni_reference_WeakGlobalReferenceTest_getPerson
+  (JNIEnv *, jobject, jlong);
+
+/*
+ * Class:     space_anyi_jni_reference_WeakGlobalReferenceTest
+ * Method:    freePerson
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL Java_space_anyi_jni_reference_WeakGlobalReferenceTest_freePerson
+  (JNIEnv *, jobject, jlong);
+
+#ifdef __cplusplus
+}
+#endif
+#endif

+ 565 - 0
doc/JNI(Java Native Interface)的参数传递和返回.md

@@ -0,0 +1,565 @@
+# JNI(Java Native Interface)的参数传递和返回
+
+### Java数据类型与C/C++本地数据类型的映射关系
+
+- Java的基本数据类型表示映射到C/C++的表示都是在原来的标识字符加上字符"j"
+
+> 例如:Java的int类型在C/C++中表示为jint类型
+
+- 对象类型使用jobject表示
+
+- "void"的表示在Java和C/C++中保持一致
+
+在头文件"jni_md.h"中有如下定义
+
+```
+ typedef long jint;
+ typedef __int64 jlong;
+ typedef signed char jbyte;
+```
+
+> 头文件"jni_md.h"在JDk的"include/linux"目录下
+
+在头文件"jni.h"中有如下定义
+
+```
+ typedef unsigned char   jboolean;
+ typedef unsigned short  jchar;
+ typedef short           jshort;
+ typedef float           jfloat;
+ typedef double          jdouble;
+ typedef jint            jsize;
+```
+
+> 头文件"jni.h"在JDk的"include"目录下
+
+映射关系如下表
+
+| Java类型 | 本地类型(C/C++类型) | JNI中定义的别名 | 描述             |
+| -------- | ------------------- | --------------- | ---------------- |
+| int      | long                | jint            | 有符号的32位表示 |
+| long     | _int64              | jlong           | 有符号的64位表示 |
+| byte     | signed char         | jbyte           | 有符号的8位表示  |
+| boolean  | unsigned char       | jboolean        | 无符号的8位表示  |
+| char     | unsigned short      | jchar           | 无符号16位表示   |
+| short    | short               | jshort          | 有符号16位表示   |
+| float    | float               | jfloat          | 32位表示         |
+| double   | double              | jdouble         | 64位表示         |
+| Object   | _jobject*           | jobject         | 对象类型         |
+| void     | void                | void            |                  |
+
+Java基本数据类型中除了boolean类型,其他数据类型都可以直接转换为C/C++的基本数据类型
+
+在C/C++中使用常量"JNI_TRUE"表示"true",常量"JNI_FALSE"表示"false"
+
+> ```
+>  //jint类型可以直接当作int类型使用
+>  int a;
+>  jint b = a;
+>  long c = b;
+>  //jboolean使用unsigned char表示
+>  //常量"JNI_TRUE"表示"true"
+>  //常量"JNI_FALSE"表示"false"
+>  jboolean ztrue = JNI_TRUE;
+>  jboolean zfasle = JNI_FALSE;
+> ```
+
+### Java数据类型的类型签名表示(与Java VM  Type Signatures规范有关)
+
+> JNI中进行对象相关的操作时需要用到Java数据类型的符号表示
+
+Java数据类型与类型签名映射关系表
+
+| Type Signature(类型签名)  |  Java Type(Java类型)  |
+| :-----------------------: | :-------------------: |
+|             Z             |        boolean        |
+|             B             |         byte          |
+|             C             |         char          |
+|             S             |         short         |
+|             I             |          int          |
+|             J             |         long          |
+|             F             |         float         |
+|             D             |        double         |
+| L fully-qualified-class ; | fully-qualified-class |
+|          [ type           |        type[]         |
+|  ( arg-types ) ret-type   |     method type`      |
+|             V             |         void          |
+
+#### 类型签名案例
+
+- `int`类型的类型签名为:`I`
+- `boolean`类型的类型签名为:`D`
+- `java.lang.String`类型的类型签名为:`Ljava/lang/String`
+
+> "L"表示为对象类型,"Ljava/lang/String"表示具体的对象类型为"java.lang.String"
+
+- `int[]`类型的类型签名为:`[I`
+
+> 一个左中括号"["表示为一维数组,完整"[int"表示为int类型的一维数组
+
+- `int[][]`类型的类型签名为:`[[I`
+
+> 两个左中括号"[["表示为二维数组,完整"[[nt"表示为int类型的二维数组
+>
+> 总结:有多少个左中括号就表示是多少维数组
+
+- `java.lang.String[]`类型的类型签名为:`[Ljava/lang/String`
+
+- 例如,有如下方法`public static void main(String[] agrs);`对应的方法类型签名为:`([Ljava/lang/String;)V`
+
+> - "()":一对小括号表示方法参数列表
+> - "[":一个左中括号表示一维数组
+> - "L":表示对象类型
+> - "java/lang/String":表示类"java.lang.String"
+> - "Ljava/lang/String;":表示"java.lang.String"这个对象类型
+> - "V":在这里表示返回值,返回类型为void
+>
+> 小括号外的类型签名表示方法的返回值类型
+>
+> 组合在一起的完整含义为,接收一个参数为字符串数组,返回值为void类型的方法
+
+- 再例如`int sum(int a,int b);`对应的类型签名为`(II)I`
+
+> 含义为有两个参数类型为int,返回值类型为int的方法
+
+- `String method(String str1,String str2);`对应的类型签名为`(Ljava/lang/String;Ljava/lang/String)Ljava/lang/String`
+
+> 参数列表有多个对象类型的参数时,对象类型的类型签名结尾需要使用分号分割
+
+### 案例:基本类型的参数传递和返回
+
+- Java代码
+
+```
+ package space.anyi.jni.parameter;
+ 
+ public class Main {
+     static {
+         System.load("/home/yangyi/JNI-learn/c/parameter/JNI_parameter.so");
+     }
+     public static void main(String[] args) {
+         BaseTypeTest baseTypeTest = new BaseTypeTest();
+         int sum = baseTypeTest.sum(1, 2);
+         System.out.println(sum);
+         boolean flag = baseTypeTest.booleanTypeTest(false);
+         System.out.println(flag);
+     }
+ }
+ class BaseTypeTest {
+     //定义一个有参数和返回值的native方法
+     native int sum(int val1,int val2);
+     //boolean类型的测试
+     native boolean booleanTypeTest(boolean flag);
+ }
+```
+
+- 生成的头文件内容
+
+生成头文件的命令:`javac -h c/parameter src/main/java/space/anyi/jni/parameter/Main.java`
+
+```
+ /* DO NOT EDIT THIS FILE - it is machine generated */
+ #include <jni.h>
+ /* Header for class space_anyi_jni_parameter_BaseTypeTest */
+ 
+ #ifndef _Included_space_anyi_jni_parameter_BaseTypeTest
+ #define _Included_space_anyi_jni_parameter_BaseTypeTest
+ #ifdef __cplusplus
+ extern "C" {
+ #endif
+ /*
+  * Class:     space_anyi_jni_parameter_BaseTypeTest
+  * Method:    sum
+  * Signature: (II)I
+  */
+ JNIEXPORT jint JNICALL Java_space_anyi_jni_parameter_BaseTypeTest_sum
+   (JNIEnv *, jobject, jint, jint);
+ 
+ /*
+  * Class:     space_anyi_jni_parameter_BaseTypeTest
+  * Method:    booleanTypeTest
+  * Signature: (Z)Z
+  */
+ JNIEXPORT jboolean JNICALL Java_space_anyi_jni_parameter_BaseTypeTest_booleanTypeTest
+   (JNIEnv *, jobject, jboolean);
+ 
+ #ifdef __cplusplus
+ }
+ #endif
+ #endif
+```
+
+
+
+- 本地方法的实现
+
+```
+ #include "space_anyi_jni_parameter_BaseTypeTest.h"
+ #include <stdio.h>
+ int sum(int a,int b){
+     return a+b;
+ }
+ JNIEXPORT jint JNICALL Java_space_anyi_jni_parameter_BaseTypeTest_sum(JNIEnv *env, jobject object, jint val1, jint val2){
+     //jint类型直接当作int类型使用
+     int temp = sum(val1,val2);
+     jint result = temp;
+     return result;
+ }
+ JNIEXPORT jboolean JNICALL Java_space_anyi_jni_parameter_BaseTypeTest_booleanTypeTest(JNIEnv *env, jobject object, jboolean flag){
+     //jboolean类型当作unsigned char类型使用
+     unsigned char val = flag;
+     printf("%d\n",val);
+     //在C/C++中使用常量"JNI_TRUE"表示"true",常量"JNI_FALSE"表示"false"
+     return val ? JNI_FALSE : JNI_TRUE;
+ }
+```
+
+
+
+- 编译为动态链接库
+
+中间编译
+
+```
+gcc -c -fPIC -I"$JAVA_HOME/include" -I"$JAVA_HOME/include/linux" -o c/parameter/JNI_parameter.o c/parameter/JNI_parameter.c
+```
+
+动态链接库编译
+
+```
+gcc -shared -fPIC -o c/parameter/JNI_parameter.so c/parameter/JNI_parameter.o -lc
+```
+
+- 运行测试:`java -cp src/main/java space.anyi.jni.parameter.Main`
+
+输出结果
+
+```
+ yangyi@debain12:~/JNI-learn$ java -cp src/main/java space.anyi.jni.parameter.Main
+ 3
+ 0
+ true
+```
+
+
+
+### 案例:引用类型(对象类型)的参数传递和返回
+
+JNI中关于对象的操作与Java的类反射机制非常相似
+
+JNI中对象抽象与Java类反射机制抽象的映射表
+
+| Java 类型反射抽象          | JNI 类型/句柄             | 说明                                                         |
+| -------------------------- | ------------------------- | ------------------------------------------------------------ |
+| `java.lang.Class`          | `jclass`                  | 表示 Java 类对象,可通过 `FindClass`、`GetObjectClass` 等获取 |
+| `java.lang.reflect.Method` | `jmethodID`               | 表示 Java 方法,可通过 `GetMethodID`、`GetStaticMethodID` 获取 |
+| `java.lang.reflect.Field`  | `jfieldID`                | 表示 Java 字段,可通过 `GetFieldID`、`GetStaticFieldID` 获取 |
+| `java.lang.Object`         | `jobject`                 | 表示 Java 对象实例的通用引用                                 |
+| `java.lang.String`         | `jstring`                 | 表示 Java 字符串对象,是 `jobject` 的子类型                  |
+| `java.lang.Throwable`      | `jthrowable`              | 表示 Java 异常对象,是 `jobject` 的子类型                    |
+| 数组类型(如 `Object[]`)  | `jarray` / `jobjectArray` | 通用数组句柄,具体类型如 `jintArray`、`jobjectArray` 等      |
+
+- Java代码,通过本地方法获取一个对象(对象类型的返回),通过本地方法输出一个对象的信息(对象类型的入参)
+
+```
+ package space.anyi.jni.parameter;
+ 
+ import java.util.Arrays;
+ 
+ public class Main {
+     static {
+         System.load("/home/yangyi/JNI-learn/c/parameter/JNI_object_parameter.so");
+     }
+     public static void main(String[] args) {
+ 
+         //JNI对象数据类型的传递
+         ObjectTest objectTest = new ObjectTest();
+         Student student = objectTest.getStudent();
+         System.out.println(student);
+         objectTest.printStudentInfo(student);
+         System.out.println(student);
+ //        objectTest.free(student);
+     }
+ }
+ class ObjectTest{
+     /**
+      * 通过JNI获取对象,返回的是全局的JNI引用,需要手动管理,有内存泄露的风险
+      * @return
+      */
+     native Student getStudent();
+     native void printStudentInfo(Student student);
+ 
+     /**
+      * 释放JNI创建的全局引用
+      * @param student
+      */
+     native void free(Student student);
+ }
+ class Student{
+     private String name;
+     private int age;
+     private float height;
+     private int[] source;
+     private String[] hobby;
+ 
+     public Student(String name) {
+         this.name = name;
+     }
+ 
+     public int getAge() {
+         return age;
+     }
+ 
+     public void setAge(int age) {
+         this.age = age;
+     }
+ 
+     public float getHeight() {
+         return height;
+     }
+ 
+     public void setHeight(float height) {
+         this.height = height;
+     }
+ 
+     public int[] getSource() {
+         return source;
+     }
+ 
+     public void setSource(int[] source) {
+         this.source = source;
+     }
+ 
+     public String[] getHobby() {
+         return hobby;
+     }
+ 
+     public void setHobby(String[] hobby) {
+         this.hobby = hobby;
+     }
+ 
+     public String getName() {
+         return name;
+     }
+ 
+     public void setName(String name) {
+         this.name = name;
+     }
+ 
+     public void info(){
+         System.out.println("My name is %s,i am %d year old,height:%f".formatted(this.name,this.age,this.height));
+     }
+ 
+     @Override
+     public String toString() {
+         return "Student{" +
+                 "name='" + name + '\'' +
+                 ", age=" + age +
+                 ", height=" + height +
+                 ", source=" + Arrays.toString(source) +
+                 ", hobby=" + Arrays.toString(hobby) +
+                 '}';
+     }
+ }
+```
+
+- 编译头文件:`javac -h c/parameter/ src/main/java/space/anyi/jni/parameter/Main.java`
+
+得到文件"space_anyi_jni_parameter_ObjectTest.h"
+
+```
+ /* DO NOT EDIT THIS FILE - it is machine generated */
+ #include <jni.h>
+ /* Header for class space_anyi_jni_parameter_ObjectTest */
+ 
+ #ifndef _Included_space_anyi_jni_parameter_ObjectTest
+ #define _Included_space_anyi_jni_parameter_ObjectTest
+ #ifdef __cplusplus
+ extern "C" {
+ #endif
+ /*
+  * Class:     space_anyi_jni_parameter_ObjectTest
+  * Method:    getStudent
+  * Signature: ()Lspace/anyi/jni/parameter/Student;
+  */
+ JNIEXPORT jobject JNICALL Java_space_anyi_jni_parameter_ObjectTest_getStudent
+   (JNIEnv *, jobject);
+ 
+ /*
+  * Class:     space_anyi_jni_parameter_ObjectTest
+  * Method:    printStudentInfo
+  * Signature: (Lspace/anyi/jni/parameter/Student;)V
+  */
+ JNIEXPORT void JNICALL Java_space_anyi_jni_parameter_ObjectTest_printStudentInfo
+   (JNIEnv *, jobject, jobject);
+ 
+ /*
+  * Class:     space_anyi_jni_parameter_ObjectTest
+  * Method:    free
+  * Signature: (Lspace/anyi/jni/parameter/Student;)V
+  */
+ JNIEXPORT void JNICALL Java_space_anyi_jni_parameter_ObjectTest_free
+   (JNIEnv *, jobject, jobject);
+ 
+ #ifdef __cplusplus
+ }
+ #endif
+ #endif
+```
+
+
+
+- 实现本地方法
+
+> C语言与C++语言使用env指针的API不一样,C语言比C++语言版本的API多一对小括号和多传递一个参数
+>
+> ```
+>  //C语言
+>  (*env)->functionName(env,args...)
+>  //C++语言
+>  env->functionName(args...)
+> ```
+
+native方法中创建的对象,如果需要在JVM中使用,需要创建全局引用,并将全局引用返回给JVM
+
+> 通过NewGlobalRefh函数创建全局引用
+>
+> ```
+>  //创建JNI全局引用,以便JVM可以使用JNI中创建的对象
+>  jobject result = (*env)->NewGlobalRef(env,student);
+>  return result;
+> ```
+>
+> 通过DeleteGlobalRef函数释放全局引用
+>
+> ```
+>  (*env)->DeleteGlobalRef(env,ref);
+> ```
+
+```
+ #include "space_anyi_jni_parameter_ObjectTest.h"
+ JNIEXPORT jobject JNICALL Java_space_anyi_jni_parameter_ObjectTest_getStudent(JNIEnv *env, jobject this){
+     printf("start:getStudent\n");
+     //C语言与C++语言使用env指针的方式不一样,C语言比C++语言版本的api多一对小括号和多传递一个参数
+     //C语言:(*env)->functionName(env,args...)
+     //C++语言:env->functionName(args...)
+     //1.通过JNIEnv指针获取指定类的jclass,通过类的类型签名指定
+     jclass class_Student = (*env)->FindClass(env,"Lspace/anyi/jni/parameter/Student;");
+     //2.获取类的构造方法,第一个参数是类的jclass,第二个参数是方法名,第三个参数是方法的类型签名
+     //构造方法的名称为:<init>,构造方法的返回值为void
+     jmethodID method_constructor_Student = (*env)->GetMethodID(env,class_Student,"<init>","(Ljava/lang/String;)V");
+     //3.调用构造方法创建对象,第一个参数是类的jclass,第二参数为jmethodID,从第三个参数开始为方法的入参
+     jstring nameStr = (*env)->NewStringUTF(env, "yangyi");
+     jobject student = (*env)->NewObject(env,class_Student,method_constructor_Student,nameStr);
+     //4.获取类的普通方法,第一个参数是jclass,第二个参数是方法的名称,第三个参数方法的类型签名
+     jmethodID student_method_setAge = (*env)->GetMethodID(env,class_Student,"setAge","(I)V");
+     //5.调用类的普通方法,第一个参数是将要调用该方法实例对象的jobject,第二个参数是方法对应的jmethodID,从第三个参数开始为方法的入参
+     (*env)->CallObjectMethod(env,student,student_method_setAge,18);
+     //6.获取类的普通字段,第一个参数是类的jcalss,第二个参数是字段的名称,第三个参数是字段的类型签名
+     jfieldID student_field_height = (*env)->GetFieldID(env,class_Student,"height","F");
+     //7.给类的普通字段设置值,第一个参数是类实例对应的jobject,第二个参数是字段对应的jfieldID,第三个参数是要设置的目标值
+     (*env)->SetFloatField(env,student,student_field_height,1.66);
+     //8.释放局部引用资源
+     (*env)->DeleteLocalRef(env, class_Student);
+     //创建JNI全局引用,以便JVM可以使用JNI中创建的对象
+     jobject result = (*env)->NewGlobalRef(env,student);
+     printf("end:getStudent\n");
+     return result;
+ }
+ 
+ 
+ JNIEXPORT void JNICALL Java_space_anyi_jni_parameter_ObjectTest_printStudentInfo(JNIEnv *env, jobject this, jobject student){
+     printf("start:printStudentInfo\n");
+     //1.调用对象的普通方法
+     //1.1获取jclass
+     jclass class_Student = (*env)->GetObjectClass(env,student);
+     //1.2获取jmethodID
+     jmethodID student_method_info = (*env)->GetMethodID(env,class_Student,"info","()V");
+     //1.3call
+     (*env)->CallObjectMethod(env,student,student_method_info);
+     //2.获取对象的字段值
+     //2.1获取jfieldID
+     jfieldID student_field_height = (*env)->GetFieldID(env,class_Student,"height","F");
+     //2.2获取对象字段对应的值
+     jfloat height = (*env)->GetFloatField(env,student,student_field_height);
+     printf("height:%f\n",height);
+     //基本类型的数组操作
+     //3.1创建数组
+     jint size = 3;
+     jintArray newArray = (*env)->NewIntArray(env, size);
+     //3.2设置数组中的值
+     //第一个参数为数组的jarray,第二个参数为数组的默认值
+     jint *source = (*env)->GetIntArrayElements(env, newArray, NULL);
+     source[0] = 90;
+     source[1] = 91;
+     source[2] = 92;
+     //3.3获取数组中的值
+     jint val1 = source[0];
+     jint val2 = source[1];
+     jint val3 = source[2];
+     //更新数组的修改,第一个参数为数组的jarray,第二个参数为C/C++中数组,第三个参数为模式(0:将数组拷贝到jarray并释放C/C++中数组的内存;1:拷贝数组但不释放内存;2:不拷贝但释放内存)
+     (*env)->ReleaseIntArrayElements(env, newArray, source,0);
+     //获取数组的长度
+     jsize length = (*env)->GetArrayLength(env, newArray);
+     jfieldID student_field_source = (*env)->GetFieldID(env,class_Student,"source","[I");
+     (*env)->SetObjectField(env,student,student_field_source,newArray);
+     //对象类型的数组操作
+     jclass class_String = (*env)->FindClass(env,"Ljava/lang/String;");
+     //第一个参数为数组的大小,第二个参数为对象的jclass,第三个参数为数组默认值
+     jobjectArray objectArray = (*env)->NewObjectArray(env, size,class_String,NULL);
+     //对象数组赋值
+     jint index = 0;
+     jstring hobby = (*env)->NewStringUTF(env,"学习");
+     //第一个参数为jarray,第二个参数为索引,第三个参数为值的jobject
+     (*env)->SetObjectArrayElement(env,objectArray,index,hobby);
+     //对象数组取值,第一个参数为jarray,第二个参数为索引
+     jobject value = (*env)->GetObjectArrayElement(env,objectArray,index);
+     jfieldID student_field_hobby = (*env)->GetFieldID(env,class_Student,"hobby","[Ljava/lang/String;");
+     (*env)->SetObjectField(env,student,student_field_hobby,objectArray);
+     //释放局部引用资源,可选
+     (*env)->DeleteLocalRef(env, class_Student);
+     printf("end:printStudentInfo\n");
+ }
+ 
+ JNIEXPORT void JNICALL Java_space_anyi_jni_parameter_ObjectTest_free(JNIEnv *env, jobject this, jobject student){
+     printf("start:free\n");
+     if(student != NULL){
+         printf("释放全局引用\n");
+         (*env)->DeleteGlobalRef(env,student);
+     }
+     printf("end:free\n");
+ }
+```
+
+
+
+- 编译动态链接库
+
+```
+ gcc -c -fPIC -I"$JAVA_HOME/include" -I"$JAVA_HOME/include/linux" -o c/parameter/JNI_object_parameter.o c/parameter/JNI_object_parameter.c
+ gcc -shared -fPIC c/parameter/JNI_object_parameter.so c/parameter/JNI_object_parameter.o -lc
+```
+
+> 得到动态链接库"JNI_object_parameter.so"
+
+- 测试输出:`java -cp src/main/java/ space.anyi.jni.parameter.Main`
+
+```
+ yangyi@debain12:~/JNI-learn$ java -cp src/main/java/ space.anyi.jni.parameter.Main 
+ start:getStudent
+ end:getStudent
+ Student{name='yangyi', age=18, height=1.66, source=null, hobby=null}
+ start:printStudentInfo
+ My name is yangyi,i am 18 year old,height:1.660000
+ height:1.660000
+ end:printStudentInfo
+ Student{name='yangyi', age=18, height=1.66, source=[90, 91, 92], hobby=[学习, null, null]}
+```
+
+
+
+### 参考资料
+
+[JNI 使用笔记](https://icejoywoo.github.io/2022/08/22/intro-to-jni.html)
+
+[案例代码仓库](https://git.anyi.space/yangyi/JNI_learn)

+ 235 - 0
src/main/java/space/anyi/jni/reference/Main.java

@@ -0,0 +1,235 @@
+package space.anyi.jni.reference;
+
+import java.util.Objects;
+
+/**
+ * @ProjectName: JNI_learn
+ * @FileName: Main
+ * @Author: 杨逸
+ * @Data:2026/3/4 21:25
+ * @Description:
+ */
+public class Main {
+    static {
+        System.load("E:\\tmp\\JNI_learn\\c\\reference\\JNI_globalReference.dll");
+        System.load("E:\\tmp\\JNI_learn\\c\\reference\\JNI_weakGlobalReference.dll");
+        System.load("E:\\tmp\\JNI_learn\\c\\reference\\JNI_localReference.dll");
+    }
+    public static void main(String[] args) {
+        //GlobalReferenceTest.test();
+        //WeakGlobalReferenceTest.testJVMGC();
+        LocalReferenceTest.test();
+    }
+}
+class LocalReferenceTest{
+    static LocalReferenceTest localReferenceTest = new LocalReferenceTest();
+
+    /**
+     * 测试在JVM中使用JNI创建的对象局部引用
+     * @description:
+     * @author: 杨逸
+     * @data:2026/03/05 21:06:10
+     * @since 1.0.0
+     */
+    static void test(){
+        Person person = localReferenceTest.getPerson();
+        System.gc();
+        try {
+            Thread.sleep(1000*5);
+        } catch (InterruptedException e) {
+            e.printStackTrace();
+        }
+        System.out.println(Objects.isNull(person));
+        System.out.println("person = " + person);
+    }
+    static void testJVMGC(){
+        while (true){
+            localReferenceTest.getPerson();
+        }
+    }
+
+    /**
+     * 在JNI中创建一个局部引用,并返回对象
+     * @return {@code Person }
+     * @description:
+     * @author: 杨逸
+     * @data:2026/03/05 22:35:30
+     * @since 1.0.0
+     */
+    native Person getPerson();
+}
+class GlobalReferenceTest{
+    static GlobalReferenceTest globalReferenceTest = new GlobalReferenceTest();
+
+    /**
+     * 测试在JVM中使用JNI创建的对象全局引用
+     * @description:
+     * @author: 杨逸
+     * @data:2026/03/05 21:06:10
+     * @since 1.0.0
+     */
+    static void test(){
+        //获取全局引用的句柄
+        long personHandler = globalReferenceTest.getPersonHandler();
+
+        //根据句柄获取全局引用对象
+        Person person = globalReferenceTest.getPerson(personHandler);
+        System.out.println("person.getName() = " + person.getName());
+        System.out.println("person.getAge() = " + person.getAge());
+        System.out.println(person);
+        //释放全局引用
+        globalReferenceTest.freePerson(personHandler);
+    }
+
+    /**
+     * 测试JNI创建的对象全局引用是否会被JVM垃圾回收
+     * @description:
+     * @author: 杨逸
+     * @data:2026/03/05 21:06:34
+     * @since 1.0.0
+     */
+    static void testJVMGC(){
+        //获取全局引用的句柄
+        long personHandler = globalReferenceTest.getPersonHandler();
+        //根据句柄获取全局引用对象
+        Person person = globalReferenceTest.getPerson(personHandler);
+        System.gc();
+        try {
+            Thread.sleep(1000*5);
+        } catch (InterruptedException e) {
+            e.printStackTrace();
+        }
+        while (true){
+            globalReferenceTest.getPersonHandler();
+        }
+    }
+    /**
+     * 在JNI中创建一个全局引用,并返回句柄
+     * @return long 全局引用的句柄
+     * @description:
+     * @author: 杨逸
+     * @data:2026/03/04 21:29:12
+     * @since 1.0.0
+     */
+    native long getPersonHandler();
+
+    /**
+     * 根据句柄获取全局引用对象
+     * @param handler 句柄
+     * @return {@code Person } 全局引用对象
+     * @description:
+     * @author: 杨逸
+     * @data:2026/03/04 21:30:09
+     * @since 1.0.0
+     */
+    native Person getPerson(long handler);
+
+    /**
+     * 释放JNI创建的全局引用
+     * @param handler 句柄
+     * @description:
+     * @author: 杨逸
+     * @data:2026/03/04 21:30:38
+     * @since 1.0.0
+     */
+    native void freePerson(long handler);
+}
+class WeakGlobalReferenceTest {
+    static WeakGlobalReferenceTest globalWeakReferenceTest = new WeakGlobalReferenceTest();
+
+    /**
+     * 测试在JVM中使用JNI创建的对象全局弱引用
+     * @description:
+     * @author: 杨逸
+     * @data:2026/03/05 21:06:10
+     * @since 1.0.0
+     */
+    static void test(){
+        //获取全局弱引用的句柄
+        long personHandler = globalWeakReferenceTest.getPersonHandler();
+
+        //根据句柄获取全局引用对象
+        Person person = globalWeakReferenceTest.getPerson(personHandler);
+        System.out.println("person.getName() = " + person.getName());
+        System.out.println("person.getAge() = " + person.getAge());
+        System.out.println(person);
+        //释放全局弱引用
+        globalWeakReferenceTest.freePerson(personHandler);
+    }
+
+    /**
+     * 测试JNI创建的对象全局引用是否会被JVM垃圾回收
+     * @description:
+     * @author: 杨逸
+     * @data:2026/03/05 21:06:34
+     * @since 1.0.0
+     */
+    static void testJVMGC(){
+        while (true){
+            globalWeakReferenceTest.getPersonHandler();
+        }
+    }
+    /**
+     * 在JNI中创建一个全局引用,并返回句柄
+     * @return long 全局弱引用的句柄
+     * @description:
+     * @author: 杨逸
+     * @data:2026/03/04 21:29:12
+     * @since 1.0.0
+     */
+    native long getPersonHandler();
+
+    /**
+     * 根据句柄获取全局弱引用对象
+     * @param handler 句柄
+     * @return {@code Person } 全局引用弱对象
+     * @description:
+     * @author: 杨逸
+     * @data:2026/03/04 21:30:09
+     * @since 1.0.0
+     */
+    native Person getPerson(long handler);
+
+    /**
+     * 释放JNI创建的全局弱引用
+     * @param handler 句柄
+     * @description:
+     * @author: 杨逸
+     * @data:2026/03/04 21:30:38
+     * @since 1.0.0
+     */
+    native void freePerson(long handler);
+}
+class Person{
+    private String name;
+    private int age;
+
+    public Person(String name, int age) {
+        this.name = name;
+        this.age = age;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public int getAge() {
+        return age;
+    }
+
+    public void setAge(int age) {
+        this.age = age;
+    }
+
+    @Override
+    public String toString() {
+        return "Person{" +
+                "name='" + name + '\'' +
+                ", age=" + age +
+                '}';
+    }
+}