私有字段和方法是否继承?

时间:2018-03-02 20:14:38

标签: java inheritance access-modifiers

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

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

然而,在我最可靠的文档来源上,这是一本书" java简而言之第6版"据说:

  

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

     

然后关于成员可访问性的正确陈述是:“所有继承的成员   并且可以访问此类中定义的所有成员。“另一种说法   这是:

     

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

     

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

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

如果我很清楚书中所说的内容,那与java文档所说的内容是否相矛盾 - 私有成员甚至都没有继承 - ? 或者我在阅读这本书时错过了什么?

2 个答案:

答案 0 :(得分:2)

成员是否被继承主要与查找过程相关。如果是一个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 } } 1}}。

这个经典的例子看起来像这样:

m()

我们可以在B的实例上调用方法B,但方法查找过程无法找到它,除非我们将A视为{ {1}}。

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

此处有一些进一步的说明,请参见§8.2

  

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

     

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

以及§8.3

  

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

     

子类可以访问超类的private字段 - 例如,如果两个类都是同一个类的成员。然而,private字段永远不会被子类继承。

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

这些澄清了继承确实与可访问性有关,但没有严格的1:1对应关系。例如,在下文中,字段x可供class B访问,但不能由class Outer { static class A { private int x; } static class B extends A { B() { super.x = 1; // accessible, but must be qualified } } } 继承(根据上述第8.3节):

@media screen and (min-width: 710px) {
  #megga-navmobile-toggle-icon { display: none; }
}
@media screen and (max-width: 710px) {
  #megga-nav-toggle-icon { display: none; }
}

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

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

答案 1 :(得分:1)

考虑

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添加了一些东西。 可以通过继承删除。它只能是不可见,它是私有的。但它仍然存在,没有消失。