10

假设我有这段代码:

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

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

我知道super()隐式放置在无参数构造函数的第一行,所以我知道Animal构造函数将被执行,因此Animal将设置 's 实例变量。

为此,我想了解,一旦这些变量已由超级构造函数 ( Animal) 初始化,这些实例变量是否将保留在 Animal 对象中或复制到子类 ( Dog)。

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

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

是这样吗?

4

4 回答 4

16

只有一个 object,它立即(从一开始)就是一个Dog实例。它具有 的所有字段Dog(不是您在这里有任何字段).的所有字段Animal

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

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

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

...它会打印出来Dog,因为对象已经是 a Dog,即使它的Dog构造函数还没有被执行。

于 2013-03-02T17:48:11.827 回答
9

您的DogextendsAnimalhead,legs变量不是私有的,因此您将从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,你可以在地址 1head作为一个变量访问,
  • 如果您有 a Dog,您可以在地址 2name处作为变量访问,
  • 如果你有一个Dog,你可以在地址 1head作为一个变量访问

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

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

我希望它澄清一点。

于 2013-03-02T17:54:52.403 回答
2

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

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

于 2013-03-02T17:49:21.293 回答
1

没有 Animal 对象,只会创建一个 Dog 对象。Dog 对象有变量legs,head 继承自Animal 对象。他们将表现得好像它是 Dog 对象的成员。由于您在 Dog 中扩展 Animal 类,因此将调用 Animal 类构造函数。并且由于 Animal 隐式扩展 Object ,因此将从 Animal 调用 Object 类构造函数。

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

于 2013-03-02T17:54:51.683 回答