Java反射获取对象成员属性,getFields()与getDeclaredFields()方法的区别

版权声明:本文为博主原创文章,未经博主允许不得转载 https://blog.csdn.net/liujun03/article/details/81512834

​ 在工作中遇到一个问题,就是你需要去判断某个字符串是不是对象的某个成员属性名,然后根据判断结果去操作这个成员属性。想了下之后,我们可以根据Java反射中的getDeclaredFields()或者getFields()方法来实现我们的需求。

​ 首先说明一下getDeclaredFields()和getFields()这两个方法的区别:

getFields(): 获取某个类的所有的public字段,其中是包括父类的public字段的

getDeclaredFields():获取某个类的自身的所有字段,不包括父类的字段

我们创建一个父类:Person , 其中name属性特意声明成了public类型

public class Person {

    public String name;
    private int age;

    // 省略get、set方法

创建子类:Student,其中studentNumber属性也声明为public

public class Student extends Person {

    public String studentNumber;
    private double grade;

    // 省略get、set方法
}

首先测试一下 getFields()方法:

public static void main(String[] args) throws IllegalAccessException {
        Student student = new Student();
        student.setGrade(99);
        student.setStudentNumber("20191223");
        student.setName("zhangsan");
        student.setAge(22);

        Field[] fields = student.getClass().getFields();
        for(Field field : fields){
            System.out.println("成员属性:"+field.getName()+" 成员属性修饰符: "+field.getModifiers()+" 成员属性值: "+field.get(student));
        }

        // 成员属性:studentNumber 成员属性修饰符: 1 成员属性值: 20191223
        // 成员属性:name 成员属性修饰符: 1 成员属性值: zhangsan
从代码可以看到,我们使用的是getFields()方法,结果中也可以看出,fields数组中只包含了public修饰的成员属性,其中除了子类本身的public类型属性,也包括了父类的public类型属性。
额,上面的成员属性修饰符返回的是int型变量,1代表的就是public,2代表的就是private,具体的对照关系可以参看java.lang.reflect.Modifier 这个类。

在测试一下 getDeclaredField()方法:

public static void main(String[] args) throws IllegalAccessException {
        Student student = new Student();
        student.setGrade(99);
        student.setStudentNumber("20191223");
        student.setName("zhangsan");
        student.setAge(22);

        Field[] fields = student.getClass().getDeclaredFields();
        for(Field field : fields){
            System.out.println("成员属性:"+field.getName()+" 成员属性修饰符: "+field.getModifiers()+" 成员属性值: "+field.get(student));
        }

}

这样直接输出的结果:

Exception in thread "main" java.lang.IllegalAccessException: Class com.baiding.test.InvokeTest can not access a member of class com.baiding.model.Student with modifiers "private"
对于私有的成员变量来说,要操作其属性值的话,就需要设置setAccessible(true);
field.setAccessible(true)就是让我们在反射时可以操作私有成员属性的值。

修改后的代码如下:

public static void main(String[] args) throws IllegalAccessException {
        Student student = new Student();
        student.setGrade(99);
        student.setStudentNumber("20191223");
        student.setName("zhangsan");
        student.setAge(22);

        Field[] fields = student.getClass().getDeclaredFields();
        for(Field field : fields){
            // 获取原来的访问控制权限
            boolean accessFlag = field.isAccessible();
            if(!field.isAccessible()) field.setAccessible(true);
            System.out.println("成员属性:"+field.getName()+" 成员属性修饰符: "+field.getModifiers()+" 成员属性值: "+field.get(student));
            field.setAccessible(accessFlag);
        }

        // 成员属性:studentNumber 成员属性修饰符: 1 成员属性值: 20191223
        // 成员属性:grade 成员属性修饰符: 2 成员属性值: 99.0
对于上述代码,增加了判断: if(!field.isAccessible()) field.setAccessible(true);
修改了字段的访问控制权限毕竟是不安全的,所以在操作结束后有必要修改回原来的访问控制权限。
从结果也可以看出:fields数组中只包含了子类Student的成员属性,不包含父类任何类型的成员属性

猜你喜欢

转载自blog.csdn.net/liujun03/article/details/81512834