继承:对象创建

时间:2013-03-02 17:46:00

标签: java inheritance instantiation instance-variables

假设我有这段代码:

class Animal {
    int legs = 4;
    int head = 1;
}

public class Dog extends Animal {
    public static void main (String []args) {
        Dog dog = new Dog();
    }
}

我知道super()隐式放在no-args构造函数的第一行,所以我知道Animal构造函数将被执行,所以Animal是将设置实例变量。

为了达到这个目的,我想了解一旦超级构造函数(Animal)初始化了这些变量,那些实例变量将保存在Animal对象中或复制到子类({{ 1}})。

在第一种情况下,对象Dog将由Animal隐式实例化,并且每当实例super();需要访问其中一个变量时,它将完成访问保留的变量在实例Dog中(在后台创建)。或者第二种情况,如果将临时创建对象Animal,则将所有实例变量(在Animal中)复制到Animal实例,然后删除临时创建的Dog实例。 / p>

我个人认为,例如Animal对象将直接链接到直接连接到对象的Dog对象。

是这样的吗?

4 个答案:

答案 0 :(得分:16)

只有一个对象,它立即(从一开始就是)一个Dog实例。它包含Dog的所有字段(不是您有任何字段) Animal的所有字段。

最初所有变量都将设置为默认值(0,null等)。然后当你到达每个类的构造函数体(在调用超类构造函数之后),执行实例变量初始化器,然后执行该类的构造函数体。

不需要复制,因为只有一个对象。例如,如果您要编写一个Animal构造函数,如下所示:

public Animal() {
    System.out.println(this.getClass());
}

...它将打印出Dog,因为该对象已经是Dog,即使它的Dog构造函数尚未执行。

答案 1 :(得分:9)

Dog扩展Animalheadlegs变量不是私有的,因此您将从Dog实例访问它们。

在实践中,会发生以下情况:

  • 您创建了Dog个实例,该实例也是Animal
  • 创建并初始化所有对象属性(包括head,并在Animal的属性之后)
  • 调用Dog的隐式构造函数(它调用super()
  • Animal的隐式构造函数称为

结果是一个对象,Dog,但也隐含Animal


Dog对象的外观(为了示例,让我们忘记Object类)。我们假设Dog也有public String name;属性。

这是Dog实例的内存映射:

Addr  Type     Name      Defined in:
------------------------
| 0 | int    | legs    | Animal
| 1 | int    | head    | Animal
| 2 | String | name    | Dog
------------------------
  • 如果您有Animal,则可以通过地址1 访问head作为变量,
  • 如果您有Dog,则可以通过地址2 访问name作为变量,
  • 如果您有Dog,则可以通过地址1
  • 访问head作为变量

Animal类主体中运行的代码只能看到地址0-1。在Dog类中运行的代码可以访问地址0-2。如果属性对于超类是private,那么该子地址将被禁止。

这个内存映射可以非常容易地向下转换对象:使用相同的内存映射,只有处理(代码和可见性)不同。

我希望它能澄清一点。

答案 2 :(得分:2)

  

一旦超级构造函数初始化了这些变量   (动物),那些实例变量将保存在Animal中   对象或复制到子类(Dog)。

首先,sub-class中的实例变量未覆盖。它们只是可见。它们不会被复制到Dog的实例中。您可以使用Dog的实例从Dog类访问它们,如果它们被标记为public,protected或no-modifier

答案 3 :(得分:1)

没有动物对象,只会创建一个Dog对象。 Dog对象有变量leg,head继承自Animal对象。他们将表现为Dog对象的成员。由于您在Dog中扩展Animal类,因此将调用Animal类构造函数。由于Animal隐式扩展了Object,因此将从Animal调用Object类构造函数。

Java如何处理这些调用是Java的内部调用,可能会因版本而异,但您应该保持相同的行为。

相关问题