1
0

6 Incheckningar a257a44f2a ... 37111fd42c

Upphovsman SHA1 Meddelande Datum
  yangyi 37111fd42c config:将编译相关的操作使用Makefile文件简化 4 veckor sedan
  yangyi 086725b0b3 feat:编译动态链接库,本地方法对象数据类型(引用类型)传递和返回 4 veckor sedan
  yangyi 3e5b4288f2 feat:编译中间代码,本地方法对象数据类型(引用类型)传递和返回的C/C++代码实现 4 veckor sedan
  yangyi fc87806aba feat:本地方法对象数据类型(引用类型)传递和返回的C/C++代码实现 4 veckor sedan
  yangyi d82e1793ce feat:生成native方法的头文件,本地方法对象数据类型(引用类型)的传递和返回 4 veckor sedan
  yangyi 94c35e0772 feat:本地方法对象数据类型(引用类型)的传递和返回 4 veckor sedan

+ 35 - 0
Makefile

@@ -0,0 +1,35 @@
+# 定义编译器
+CC := gcc
+
+# 定义编译选项
+CFLAGS := -c -fPIC -I"$(JAVA_HOME)/include" -I"$(JAVA_HOME)/include/linux"
+LDFLAGS := -shared -fPIC -lc
+
+# 定义源文件列表(不带扩展名)
+SOURCES := \
+    c/helloWorld/JNI_Hello_World \
+    c/parameter/JNI_parameter \
+    c/parameter/JNI_object_parameter
+
+# 生成目标文件列表
+OBJECTS := $(addsuffix .o, $(SOURCES))
+
+# 生成共享库文件列表
+SHARED_LIBS := $(addsuffix .so, $(SOURCES))
+
+# 默认目标:构建所有共享库
+all: $(SHARED_LIBS)
+
+# 构建共享库的通用规则
+%.so: %.o
+	$(CC) $(LDFLAGS) -o $@ $<
+
+# 构建目标文件的通用规则
+%.o: %.c
+	$(CC) $(CFLAGS) -o $@ $<
+
+# 清理生成的文件
+clean:
+	rm -f $(OBJECTS) $(SHARED_LIBS)
+
+.PHONY: all clean

+ 92 - 0
c/parameter/JNI_object_parameter.c

@@ -0,0 +1,92 @@
+#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");
+}

BIN
c/parameter/JNI_object_parameter.o


BIN
c/parameter/JNI_object_parameter.so


+ 37 - 0
c/parameter/space_anyi_jni_parameter_ObjectTest.h

@@ -0,0 +1,37 @@
+/* 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

+ 98 - 5
src/main/java/space/anyi/jni/parameter/Main.java

@@ -1,15 +1,27 @@
 package space.anyi.jni.parameter;
 
+import java.util.Arrays;
+
 public class Main {
     static {
         System.load("/home/yangyi/JNI-learn/c/parameter/JNI_parameter.so");
+        System.load("/home/yangyi/JNI-learn/c/parameter/JNI_object_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);
+        //JNI基本数据类型的传递
+//        BaseTypeTest baseTypeTest = new BaseTypeTest();
+//        int sum = baseTypeTest.sum(1, 2);
+//        System.out.println(sum);
+//        boolean flag = baseTypeTest.booleanTypeTest(false);
+//        System.out.println(flag);
+
+        //JNI对象数据类型的传递
+        ObjectTest objectTest = new ObjectTest();
+        Student student = objectTest.getStudent();
+        System.out.println(student);
+        objectTest.printStudentInfo(student);
+        System.out.println(student);
+//        objectTest.free(student);
     }
 }
 class BaseTypeTest {
@@ -18,3 +30,84 @@ class BaseTypeTest {
     //boolean类型的测试
     native boolean booleanTypeTest(boolean flag);
 }
+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) +
+                '}';
+    }
+}
+