Java反射机制的getFields、getDeclaredFields以及setAccessible方法

986 阅读2分钟

创建一个父类UpperKk

public class UpperKk {

    public short upperS;
    public byte upperB;
}

创建一个子类Kk,继承UpperKk

public class Kk extends UpperKk{

    private int i;
    private boolean flag;
    public long l;
}

单独创建一个测试类,测试getDeclaredFields()

public class T {

    public static void main(String[] args) throws Exception{
        Class clz = Class.forName("Kk");
        Kk k = (Kk) clz.getDeclaredConstructor().newInstance();

        Field[] fields = k.getClass().getDeclaredFields();
        for(Field f:fields){
            System.out.println("属性名称:"+f.getName());
            System.out.println("属性类型:"+f.getType().getName());
            System.out.println("---------------------------");
        }
    }
}

运行结果,可以取到子类所有属性的名称和类型

属性名称:i
属性类型:int
---------------------------
属性名称:flag
属性类型:boolean
---------------------------
属性名称:l
属性类型:long
---------------------------

如果要取属性的值,可不可以呢?

public class T {

    public static void main(String[] args) throws Exception{
        
        Class clz = Class.forName("Kk");
        //在jdk9之后clz.newInstance()被废弃,所以使用下列方法创建实例
        Kk k = (Kk) clz.getDeclaredConstructor();

        Field[] fields = k.getClass().getDeclaredFields();
        for(Field f:fields){
            //f.setAccessible(true);
            System.out.println("属性名称:"+f.getName());
            System.out.println("属性类型:"+f.getType().getName());
            System.out.println("属性值:"+f.get(k));
            System.out.println("---------------------------");
        }
    }
}

运行报错,提示说取不到属性为private的值

属性名称:i
属性类型:int
Exception in thread "main" java.lang.IllegalAccessException: class Ttt cannot access a member of class Kk with modifiers "private"
	at java.base/jdk.internal.reflect.Reflection.newIllegalAccessException(Reflection.java:361)
	at java.base/java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:591)
	at java.base/java.lang.reflect.Field.checkAccess(Field.java:1075)
	at java.base/java.lang.reflect.Field.get(Field.java:416)
	at Ttt.main(Ttt.java:15)

f.setAccessible(true)取消注释,运行成功,子类中的所有属性的值都取到了

属性名称:i
属性类型:int
属性值:0
---------------------------
属性名称:flag
属性类型:boolean
属性值:false
---------------------------
属性名称:l
属性类型:long
属性值:0
---------------------------

测试getFields()

public class T {

    public static void main(String[] args) throws Exception{
        
        Class clz = Class.forName("Kk");
        //在jdk9之后clz.newInstance()被废弃,所以使用下列方法创建实例
        Kk k = (Kk) clz.getDeclaredConstructor();

        Field[] fields = k.getClass().getFields();
        for(Field f:fields){
            System.out.println("属性名称:"+f.getName());
            System.out.println("属性类型:"+f.getType().getName());
            System.out.println("属性值:"+f.get(k));
            System.out.println("---------------------------");
        }
    }
}

运行成功,取到了子类和父类中的public的属性

属性名称:l
属性类型:long
属性值:0
---------------------------
属性名称:upperS
属性类型:short
属性值:0
---------------------------
属性名称:upperB
属性类型:byte
属性值:0
---------------------------

总结

getFields()可以取到子类和父类中的public的属性

getDeclaredFields()取不到父类中的属性,可以取到子类中的所有属性的类型和名称,但是默认情况下取不到private的属性的值,需要修改setAccessible(true)才可以