今天有朋友问,继承会继承父类的私有属性和私有方法吗。回答当然是可以的,只是不能直接访问(例如对于父类的私有属性,可以借助从父类中继承的get方法来获得该值)。
当时也想到可以通过反射的方式来获取父类中私有属性的值。一开始使用getDeclaredFileds()
,但发现只能获取子类的相关的属性对象,后面结合getSuperclass()
方法先获取父类的字节码对象进而获取了子类中的所有属性对象。具体代码如下:
通过 getDeclaredFileds()
方法获取属性对象
父类:
public class Person {
public String name;
private int age;
}
子类:
public class Student extends Person {
public String className;
private String gender;
}
测试:
public class Demo {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
Student student = new Student();
// 通过子类的字节码对象获取获取所有属性
Class<Student> studentClass = Student.class;
Field[] declaredFields = studentClass.getDeclaredFields();
for (Field declaredField : declaredFields) { // 打印所有的属性字段
System.out.println(declaredField);
}
}
}
运行结果:
public java.lang.String Demo.Student.className
private java.lang.String Demo.Student.gender
可以看到通过getDeclaredFileds()
方法可以获取当前类私有属性对象和公有属性对象,当不能获取父类相关的属性对象。
结合getSuperclass()
方法获取父类的属性对象
由于反射机制只能获取当前类的属性对象,为了获取其父类的属性对象就需要先通过getSuperclass
获取该当前类的父类字节码对象,因为类存在对继承这里使用了while(clazz != null)
遍历了所有的父类字节码对象。具体代码如下:
public class Demo {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
Student student = new Student();
Class clazz = Student.class;
List fieldsList = new ArrayList<Field[]>(); // 保存属性对象数组到列表
while (clazz != null) { // 遍历所有父类字节码对象
Field[] declaredFields = clazz.getDeclaredFields(); // 获取字节码对象的属性对象数组
fieldsList.add(declaredFields);
clazz = clazz.getSuperclass(); // 获得父类的字节码对象
}
for (Object fields:fieldsList) { // 打印当前类以及其父类的多有属性对象
Field[] f = (Field[]) fields;
for (Field field : f) {
System.out.println(field);
}
}
}
}
结果:
public java.lang.String Demo.Student.className
private java.lang.String Demo.Student.gender
public java.lang.String Demo.Person.name
private int Demo.Person.age
上述代码还可以进行改进,可以将Filed[]
数组转换为List<>
然后再将其拼接至ArrayList
上,这样后面遍历Filed
对象也不用嵌套循环了。
public class Demo {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
Student student = new Student();
Class clazz = Student.class;
List fieldsList = new ArrayList<Field>();
while (clazz != null) { // 遍历所有父类字节码对象
Field[] declaredFields = clazz.getDeclaredFields();
fieldsList.addAll(Arrays.asList(declaredFields)); //将`Filed[]`数组转换为`List<>`然后再将其拼接至`ArrayList`上
clazz = clazz.getSuperclass(); // 获得父类的字节码对象
}
for (Object field : fieldsList) { // 打印当前类以及其父类的多有属性对象
System.out.println(field);
}
}
}
参考
Java反射机制获取父类属性: https://www.jianshu.com/p/6fe3e0e185ac