我的JNI学习摘要(三) ---- 操作对象

本文详细介绍了如何使用Java实现Employee类,并通过JNI技术与C/C++交互,特别关注了如何在C/C++代码中访问Java类的成员变量和调用方法。包括编译、生成头文件、获取类对象、访问实例变量、调用静态方法等关键步骤,以及可能遇到的异常处理。最后,通过测试代码验证了实现的有效性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

仅供自己学习使用!

创建Employee类: Employee.java

public class Employee{

        private String name;
        private double salary;

        public Employee(String name, double salary){
                this.name = name;
                this.salary = salary;
        }

        public native void raiseSalary(double byPercent);

        public void print(){
                System.out.println(name + " " + salary);
        }

        static{
                System.loadLibrary("Employee");
        }
}

对Employee.java进行编译:
$ javac Employee.java
生成Employee.h的头文件:

$ javah Employee

得到Employee.h:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class Employee */

#ifndef _Included_Employee
#define _Included_Employee
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     Employee
 * Method:    raiseSalary
 * Signature: (D)V
 */
JNIEXPORT void JNICALL Java_Employee_raiseSalary
  (JNIEnv *, jobject, jdouble);  /* 这里的第二个参数是jobject而不是先前的jclass,是因为静态方法得到的是类的引用,非静态方法得到的是隐含的this参数对象的引用 */

#ifdef __cplusplus
}
#endif
#endif

JNI要求通过特殊的JNI函数来获取和设置Employee类中的变量salary的值

由于salary是double类型的,因此可以使用GetDoubleField和SetDoubleField函数,类似的还有GetIntField/SetIntField等等,其语法如下:

x = (*env)->GetXxxField(env, this_obj, fieldID);

(*env)->SetXxxField(env, this_obj, fieldID, x);

有两种方法得到class对象:

1. jclass class_Employee = (*env)->GetObjectClass(JNIEnv *env, jobject obj); 通过对象获取这个类,可以返回任意对象的类

2. jclass class_String = (*env)->FindClass(env, "java/lang/String");  可以通过字符串的形式来制定类名 

fieldID 是一个特殊类型的值,jfieldID表示结构中的一个域(域可以理解为一个对象的字段,属性或者方法)

jfieldID id_salary = (*env)->GetFieldID(env, class_Employee, "salary", "D");  获取实例对象的域ID, salary是域的名称,D是域的类型(double)

需要注意的是,非静态的实例化后的对象,可能产生的异常有

1) NoSuchFieldError  找不到指定的域
2) ExceptionInInitializerError 因为异常而导致类初始化失败
3) OutOfMemoryError内存不足。


纵观所述: Employee.c的代码是:

#include "Employee.h"
#include <stdio.h>

JNIEXPORT void JNICALL Java_Employee_raiseSalary(JNIEnv * env, jobject this_obj, jdouble byPercent)
{
        /* 通过类获得 salary 的fieldID */
        jclass class_Employee = (*env)->GetObjectClass(env, this_obj);

        /* 通过类获得 salary 的fieldID */
        jfieldID id_salary = (*env)->GetFieldID(env, class_Employee, "salary", "D");

        /* 获得引用对象中 salary 的值 */
        jdouble salary = (*env)->GetDoubleField(env, this_obj, id_salary);

        salary *= 1 + byPercent / 100;

        /* set the field value*/
        (*env)->SetDoubleField(env, this_obj, id_salary, salary);
}

其中“通过类获得salary的fieldID” 比较的不好理解,虽然我不知道这个具体是什么意思,但我把这个fieldID理解为地址偏移量,这个偏移量只能是针对类的,而不是针对具体的对象------例如我们假设偏移量是100, 现在又2个对象 obj1和obj2, obj1和obj2都是 Employee的对象,然而他们的起始地址肯定是不同的,如何才能得到这两个对象中salary的值呢?程序只需要知道这两个对象的起始地址就可以了(而这个地址,程序肯定是知道的) 比如obj1的其实地址为10000,那么要引用obj1的salary变量只需要10000+100即可,obj2的起始地址是20000,则obj2的salary只需要20000+100就可以引用到!(个人方便理解)


测试是否通过:TestEmployee.java


public class TestEmployee{
        public static void main(String[] args){
                Employee[] staff = new Employee[3];
                staff[0] = new Employee("Harry", 35000);
                staff[1] = new Employee("Carl", 75000);
                staff[2] = new Employee("Potter", 38000);

                for (Employee e : staff)
                        e.raiseSalary(5);
                for (Employee e : staff)
                        e.print();
        }
}


刚才在Employee.c中提到的this_obj 是对象的引用,这里在new出来3个对象即是this_obj的引用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值