首页 > 解决方案 > `Sub` 和 `Super` 中定义的私有方法,这两个方法都可以在 Sub 的 Object 上调用,那为什么私有方法说不被继承呢?

问题描述

根据Oracle 教程

子类不继承其父类的私有成员。但是,如果超类具有访问其私有字段的公共或受保护方法,则子类也可以使用这些方法。

[问题] 对于类关系Sub extends Super,据了解,Oracle 文档这样说只是为了支持“只能覆盖继承的方法”这一事实,但这是一种误导性陈述,好像它似乎暗示 =>如果一个方法不是继承的,那么它就不会作为 Sub 类的对象的行为存在,如果是这样,那么它决不能在 Sub 类的对象上调用。但是 Super 类中的方法可以在 Sub 类的 Object 上调用 Super 类定义的私有方法。请参考以下几点和相关代码,并建议我的理解是否存在一些差距?

我一直把继承理解为以下3点

  1. 一个类Sub继承所有实例方法和字段(包括私有的)。
  2. 如果一个方法是私有的,Super那么它是不可见的,Sub但这并不意味着一个对象Sub没有该行为。

第 1 点和第 2 点的代码

public class Super{
    private void privateMethod(){
        System.out.println("private method defined in Super");
    }
    public void m(){
        privateMethod();
    }
}

public class Sub extends Super{

} 
public void Other{
    public static void main(String[] args){
        Sub s = new Sub();
        s.m(); 
    }
}

我们创建了一个对象Subm()被继承Sub,其public含义是它可以被外部的代码访问Super。在调用m()时,我们可以调用privateMethod(). 如果私有方法没有被继承,那么就会发生一些运行时异常,但事实并非如此。

  1. Overriding仅适用于类中的可见实例方法Sub。如果一个方法是不可见的,Sub并且在两个类中都定义了Super,那么该对象具有两种能力,并且这两种方法都可以由可以访问特定方法的代码调用(参考下面的代码)

第 3 点的代码

public class Super{
    private void privateMethod(){
        System.out.println("private method defined in Super");
    }
    public void m(){
        privateMethod();
    }
}

public class Sub extends Super{
    private void privateMethod(){
        System.out.println("private method defined in Sub");
    }
    public void m2(){
        privateMethod();
    }
} 
public class Other{
    public static void main(String[] args){
        Sub s = new Sub();
        s.m(); // m() will invoke private method of Super
        s.m2(); // m2() will invoke private method of Sub
    }
}

Sub类不继承私有方法Super意味着不能在对象上调用方法,Sub因为行为不是继承的,因此不是(不属于)对象的一部分。上面我们看到情况并非如此。

标签: javainheritanceprivate-methods

解决方案


我认为关键的区别在于 Java 语言规范如何使用术语“继承”。(请注意,JLS 是权威文档,而不是 Java 教程。)

JLS 8.2,班级成员说:

声明为私有的类的成员不会被该类的子类继承。

但是,在描述new运算符的行为时,JLS 15.9.4,类实例创建表达式的运行时评估说(强调我的):

新对象包含在指定类类型及其所有超类中声明的所有字段的新实例。

这意味着超类的字段不被子类继承,但子类的实例对象仍然包含这些字段。同样的概念也适用于私有方法

尽管可以在子类的实例上调用来自超类的私有方法,但该方法在形式上并不是该子类的一部分。私有方法仍然属于超类。

这是因为子类型(“is-a”)关系。子类型实例是超类型的实例。该类不会将这些成员继承到自身中,但该类的实例仍然包含它们。


推荐阅读