superClass的私有成员是否由子类继承... Java?

时间:2013-01-03 16:15:13

标签: java inheritance private access-control access-specifier

我已经完成了这个:

Do subclasses inherit private fields?

但我仍然感到困惑......

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

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

例如......

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的SCJP Book& Bert ......它说它们不是继承的......我发布了这个更新,因为仍然有很多人说是......

5 个答案:

答案 0 :(得分:6)

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

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

答案 1 :(得分:4)

由于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.

因此编译后的类不包含继承的字段。另一方面,当创建对象时,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 ...

答案 2 :(得分:1)

两者都没有 - 对象的大小包含一些开销。但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);
}

答案 3 :(得分:0)

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

  

威尔   b的大小为4   d的大小为8   要么   d的大小也只有4个?

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

答案 4 :(得分:0)

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

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

class Base {
  protected int i;
}

class Derived extends Base {
  int j;
}

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