superClass的私有成员是否由子类inheritance… Java?

我经历过这个:

子类是否inheritance私有字段?

但我还是很困惑……

我说的只是inheritance而不是访问。 我知道他们在副class上并不明显。

但是子类’对象是否拥有超类中那些私有成员的自己的副本?

例如…

class Base { private int i; } class Derived extends Base { int j; } 

现在,

 Base b = new Base(); Derived d = new Derived(); 

int的大小是4

现在,

b的大小是4,d的大小是8

要么

d的大小也只有4?

当然,当我说b和d而不是引用时,我正在谈论堆上的对象。

更新:我刚刚阅读了Kathy Sierra和Bert的SCJP书……它说它们不是inheritance的……我发布了这个更新,因为仍然有很多人说是的…

是的,子类的实例将具有父类的私有字段的副本。

但是它们对子类是不可见的,因此访问它们的唯一方法是通过父类的方法。

由于JVM规范, class文件以这种方式构建:

 ClassFile { u4 magic; u2 minor_version; u2 major_version; u2 constant_pool_count; cp_info constant_pool[constant_pool_count-1]; u2 access_flags; u2 this_class; u2 super_class; u2 interfaces_count; u2 interfaces[interfaces_count]; u2 fields_count; field_info fields[fields_count]; u2 methods_count; method_info methods[methods_count]; u2 attributes_count; attribute_info attributes[attributes_count]; } 

super_class字段包括:

`对于类,super_class项的值必须为零或必须是constant_pool表的有效索引。 如果super_class项的值非零,则该索引处的constant_pool条目必须是CONSTANT_Class_info(§4.4.1)结构,表示此类文件定义的类的直接超类。 直接超类或其任何超类都不能在其ClassFile结构的access_flags项中设置ACC_FINAL标志。

如果super_class项的值为零,则此类文件必须表示Object类,这是唯一没有直接超类的类或接口。

对于接口,super_class项的值必须始终是constant_pool表的有效索引。 该索引处的constant_pool条目必须是表示Object类的CONSTANT_Class_info结构

更有趣的是fields[]部分:

Each value in the fields table must be a field_info (§4.5) structure giving a complete description of a field in this class or interface. The fields table includes only those fields that are declared by this class or interface. It does not include items representing fields that are inherited from superclasses or superinterfaces.

因此编译的类不包含inheritance的字段 。 另一方面,当创建对象时, private超级字段在内存中。 为什么? 让我们想象一下这个例子:

  classs A { int a; A(int a) { this.a = a; } void methodA() { System.out.println("A is: " + a); } } classs B extends A { int b; B(int b) { super(10); this.b = b; } void methodB() { super.methodA(); System.out.println("B is: " + b); } } 

输出应为: A is: 10 \n B is ...

两者都没有 – 对象的大小包括一些开销。 但Derived将占用比Base更多的空间。

运行快速测试,看起来Base的大小约为20个字节,Derived的大小约为28个字节。 请注意,这些结果可能因不同的JVM而异。

 public static void main(String[] args) throws InterruptedException { int size = 500000; double mem; mem = Runtime.getRuntime().freeMemory(); Base[] base = new Base[size]; for (int i = 0; i < size; i++) { base[i] = new Base(); } System.out.println((mem - Runtime.getRuntime().freeMemory()) / size); System.gc(); Thread.sleep(100); System.gc(); mem = Runtime.getRuntime().freeMemory(); Derived[] derived = new Derived[size]; for (int i = 0; i < size; i++) { derived[i] = new Derived(); } System.out.println((mem - Runtime.getRuntime().freeMemory()) / size); } 

是的,Derived类将具有Base类的私有字段。 如果Derived定义了公共getter和setter,您将能够使用Derived类中的该字段。

b的大小是4,d的大小是8还是d的大小也只有4?

它是Java,而不是C.您无法轻易估计堆中对象的大小。 它将大于4或8个字节。

不,私有字段设计为可在其声明的类上访问。 在类之外(包括派生类)可以访问它们的唯一方法是通过公共方法。

如果要使派生类inheritance的基类中的成员使用“protected”而不是private。 代码应该是:

 class Base { protected int i; } class Derived extends Base { int j; } 

“受保护的”访问修饰符允许inheritance成员并为其分配自己的访问修饰符。