5

我试图从 Thinking in Java 中理解这个例子

package c07;
import com.bruceeckel.simpletest.*;

class Meal {
    Meal() { System.out.println("Meal()"); }
}

class Bread {
    Bread() { System.out.println("Bread()"); }
}

class Cheese {
    Cheese() { System.out.println("Cheese()"); }
}

class Lettuce {
    Lettuce() { System.out.println("Lettuce()"); }
}

class Lunch extends Meal {
    Lunch() { System.out.println("Lunch()"); }
}

class PortableLunch extends Lunch {
    PortableLunch() { System.out.println("PortableLunch()");}
}

public class Sandwich extends PortableLunch {
    private static Test monitor = new Test();
    private Bread b = new Bread();
    private Cheese c = new Cheese();
    private Lettuce l = new Lettuce();

    public Sandwich() {
        System.out.println("Sandwich()");
    }

    public static void main(String[] args) {
        new Sandwich();
        monitor.expect(new String[] {
          "Meal()",
          "Lunch()",
          "PortableLunch()",
          "Bread()",
          "Cheese()",
          "Lettuce()",
          "Sandwich()"
        });
    }
}

正如我从 Java 语言规范中了解到的那样,执行顺序从加载包含 main 方法的类开始。然后必须初始化这个类的所有静态变量和成员变量(在此之前必须初始化超类的所有成员变量,尽管在这种情况下没有这些成员变量)。

所以我认为b,c会在开始执行l之前被初始化。main不过,从输出来看,情况似乎并非如此。我错过了什么吗?

4

3 回答 3

5

不,b并且c实例变量。

没有自动实例化包含main. 只有静态变量被初始化。就好像某个外部来电者写道:

Sandwich.main(args);

所以当你写:

那么这个类的所有静态变量和成员变量都必须初始化

……那是错误的。只有静态变量被初始化——就像平常一样。

于 2012-10-02T18:40:32.683 回答
0

示例输出是正确的。以下是重要的规则:

  • 创建类时,必须首先调用超类的构造函数。这冒泡Object上课

  • 在调用构造函数之前,会调用成员变量初始化。

此示例中不static涉及 s,除了技术monitor.

于 2012-10-02T18:41:37.833 回答
0

JLS #12.4.1。初始化发生时

类或接口类型 T 将在以下任何一项第一次出现之前立即初始化:

  • T 是一个类,并创建了一个 T 的实例。
  • T 是一个类,并且调用了 T 声明的静态方法。
  • 分配了一个由 T 声明的静态字段。
  • 使用了由 T 声明的静态字段,并且该字段不是常量变量(第 4.12.4 节)。
  • T 是一个顶级类(第 7.6 节),并且执行在词法上嵌套在 T(第 8.1.3 节)中的断言语句(第 14.10 节)。

JLS #12.5。创建新的类实例

每当创建一个新的类实例时,都会为其分配内存空间,并为该类类型中声明的所有实例变量和该类类型的每个超类中声明的所有实例变量(包括所有可能隐藏的实例变量)分配空间( §8.3)。

于 2012-10-02T18:45:48.857 回答