【问题标题】:Are private fields and methods inherited? [duplicate]私有字段和方法是否被继承? [复制]
【发布时间】:2018-08-11 02:42:33
【问题描述】:

我做了一些研究,以了解私有实例字段和方法是否由子类从其超类继承。

实际上,我在不同的论坛上给出了相互矛盾的答案,但最有说服力的是,就像 java 文档所说,私有字段和方法永远不会被继承,但是子类的实例为私有字段和方法分配了一些内存超类。

然而,在我最可靠的文档来源,即“java in a nutshell 6th edition”一书中,它说:

这种潜在的不可访问成员的存在似乎与类的成员在类的主体内总是可访问的声明相冲突。为了消除这种混淆,我们将“继承成员”定义为那些可访问的超类成员。

那么关于成员可访问性的正确说法是:“所有继承的成员 并且该类中定义的所有成员都是可访问的。”另一种说法 这是:

• 一个类继承所有实例字段和实例方法(但不是构造函数) 它的超类。

• 类的主体始终可以访问它声明的所有字段和方法 本身。它还可以访问从其继承的可访问字段和成员 超类。

因此,根据我的理解,我得出的结论是,子类从其超类继承了所有字段和方法(包括私有的),但不知何故,子类的主体无法访问私有(以及最终其他不可见的)成员超类。

如果我很好地理解了这本书的内容,这与 java 文档所说的——私有成员甚至没有被继承——不是矛盾吗? 还是我在看书的时候错过了什么?

【问题讨论】:

  • 他们是。它们不能从子类访问,但它们确实是继承的。
  • 就像 java 文档所说,私有字段和方法永远不会被继承”你能说明你在哪里读到的吗?
  • 嘿 csmckelvey 它来自“Java in a Nutshell”一书,第 6 版,第 1 部分第 3 章。虽然找不到 pdf 链接
  • 您的“简而言之”书中的 sn-p(实际上是 Java 语言规范)正在以不同于我们某些/许多/大多数人直观预期的方式定义“继承”。他们将其与可访问性联系起来。私有成员保留在超类中;因为它不能被子类访问,它根据定义不被继承。

标签: java inheritance access-modifiers


【解决方案1】:

成员是否被继承主要与查找过程有关。如果例如class B extends A,当语言规范说私有成员不被继承时,这意味着A的私有成员只属于B的实例,而将它们视为A

这方面的经典示例如下所示:

class B extends A {}

class A {
    private void m() {}
    
    public static void main(String[] args) {
        B b = new B();
        b.m(); // error: "cannot find symbol"
        A a = b;
        a.m(); // fine: m() is a member of A
    }
}

确实有一个方法m(),我们可以在B 的实例上调用它,但是方法查找过程找不到它,除非我们将B 视为A

使用私有字段,对象的内存表示将包括其超类的私有字段,即使我们说它们不是 JLS 术语中的继承。

§8.2 中有一些进一步的说明:

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

只有声明为 protectedpublic 的类的成员才会被声明在该类所在包之外的包中声明的子类继承。

以及§8.3:

一个类从它的直接超类和直接超接口继承超类和超接口的所有非私有字段,这些字段都可以被类中的代码访问,并且不会被类中的声明隐藏。

超类的private 字段可能可供子类访问 - 例如,如果两个类都是同一类的成员。尽管如此,private 字段永远不会被子类继承。

§8.4.8 也有类似的方法规则。)

这些说明继承确实与可访问性有关,但没有严格的 1:1 对应关系。例如,在下面,x 字段可以访问,但不能被 class B 继承(根据上面的 §8.3):

class Outer {
    static class A {
        private int x;
    }
    static class B extends A {
        B() {
            super.x = 1; // accessible, but must be qualified
        }
    }
}

一种说法是,可访问性是继承的必要条件,但不是充分条件。 (换句话说,继承需要可访问性,但反之则不然。)

通俗地说,私有成员是继承的可能是正确的,因为 1)子类对象存储其超类的私有变量,2)可以在子类实例上调用超类的私有方法。然而,这不是 JLS 使用这个词的方式。

【讨论】:

    【解决方案2】:

    考虑

    class A {
       private int x;
       public A() {
         x = 10;
       }
       public int foo() {
          return x * 2;
       }
    }
    
    public class B extends A {
       public B() {
          super();  // Calls A's constructor assigning x.
          // anything
       }
    }
    
    int n = B().foo();  // n == 20
    

    很明显B 的实例确实带有成员x 及其值。如果B 不这样做,则无法运行继承的方法foo,因为该方法在A 中的实现需要x 的值。

    确实,B 不能直接访问x。但只要它有任何(传递地)依赖于该值的方法,通过从A 继承,它就必须为x 分配存储空间。

    换句话说,BA 加上了一些东西。 没有任何东西可以通过继承删除。它只能不可见,它是私有的。但它还在那里,没有消失。

    【讨论】:

    • 感谢您的回答。这是有道理的,但它与 oracle 文档中明确指出的内容并不矛盾:“子类不继承其父类的私有成员。”?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-13
    • 2020-10-25
    • 2018-06-14
    • 2013-01-09
    • 2013-01-01
    相关资源
    最近更新 更多