子类拥有父类对象所有的属性和方法,但无法访问

worshipone / 2024-04-24 / 原文

原链接

前言

JavaGuide中关于继承有如下描述:

  1. 子类拥有父类对象所有的属性和方法(包括私有属性和私有方法),但是父类中的私有属性和方法子类是无法访问,只是拥有。

尝试验证这一观点。

对象初始化

首先从对象初始化开始思考,一般继承某个父类的子类对象初始化时是按照以下顺序:

  1. 父类的静态变量和常量以及父类的静态代码块
  2. 子类的静态变量和常量以及子类的静态代码块
  3. 父类的变量赋默认值和父类代码块
  4. 父类的构造方法
  5. 子类的变量赋默认值和父类代码块
  6. 子类的构造方法

既然按照对象初始化顺序来说,子类的构造方法被调用的时候必然有一个父类对象被构造,那么必然有办法在子类构造时对父类的变量进行赋值。

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);
    }
}

其实从这里就可以知道子类是拥有父类的私有属性的了,只是因为访问控制限制无法直接访问这个属性。
但是除了这个方法以外,我还有什么办法去佐证这个观点呢?当然有啦,而且还不止一种呢,我知道的就有两个办法:

  1. 直接查看字节码
  2. 使用反射获取
    下面展示如何使用反射获取父类的属性的示例代码:
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