今天有朋友問,繼承會繼承父類的私有屬性和私有方法嗎。回答當然是可以的,只是不能直接訪問(例如對於父類的私有屬性,可以借助從父類中繼承的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