前言
最近在看JavaGuide进行基础知识的回顾,注意到一个有意思的观点,原文如下
关于继承如下 3 点请记住:
- 子类拥有父类对象所有的属性和方法(包括私有属性和私有方法),但是父类中的私有属性和方法子类是无法访问,只是拥有。
于是我就开始尝试验证这一观点
对象初始化
首先从对象初始化开始思考,一般继承某个父类的子类对象初始化时是按照以下顺序
- 父类的静态变量和常量以及父类的静态代码块
- 子类的静态变量和常量以及子类的静态代码块
- 父类的变量赋默认值和父类代码块
- 父类的构造方法
- 子类的变量赋默认值和父类代码块
- 子类的构造方法
既然按照对象初始化顺序来说,子类的构造方法被调用的时候必然有一个父类对象被构造,那么必然有办法在子类构造时对父类的变量进行赋值。
这个时候我突然想到了Java
如果不指定构造方法,会默认给每个类提供一个无参构造方法,那如果我的父类只有有参构造方法又会如何呢?
使用有参构造方法
首先我准备好了父类,这个父类里面只有一个parentName
的属性,同时制定一个有参构造方法,代码如下:
public class Parent {
private String parentName;
public Parent(String parentName) {
this.parentName = parentName;
}
}
然后我准备了子类继承父类,这个时候有意思的事情发生了,子类必须提供一个带参的构造方法来构造父类对象,同时要在这个带参构造方法里面通过super
关键字调用父类的构造方法,否则编译会失败,最终代码如下:
public class Child extends Parent{
public Child(String parentName) {
super(parentName);
}
}
其实从这里就可以知道子类是拥有父类的私有属性的了,只是因为访问控制限制无法直接访问这个属性。
但是除了这个方法以外,我还有什么办法去佐证这个观点呢?当然有啦,而且还不止一种呢,我知道的就有两个办法
- 直接查看字节码
- 使用反射获取
使用反射获取
由于篇幅问题,这里就展示怎么使用反射获取父类的属性的示例代码,如果对通过字节码验证这个观点感兴趣可以给我留言:
Child child = new Child("David");
try {
// 获取父类Class对象
Class parentClass = child.getClass().getSuperclass();
// 获取父类的属性
Field field = parentClass.getDeclaredField("parentName");
// 解除访问限制
field.setAccessible(true);
// 输出
System.out.println(field.get(child));
} catch (NoSuchFieldException e) {
// 这里只是演示用,实际开发时需要将错误信息打印到日志文件
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
输出结果
David