【问题标题】:Order of execution in JavaJava中的执行顺序
【发布时间】:2012-09-23 15:42:26
【问题描述】:

我正在努力理解this example from 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 方法的类开始。然后必须初始化这个类的所有静态变量和成员变量(在此之前必须初始化超类的所有成员变量,尽管在这种情况下没有这些成员变量)。

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

【问题讨论】:

    标签: java order-of-execution


    【解决方案1】:

    JLS # 12.4.1. When Initialization Occurs

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

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

    JLS # 12.5. Creation of New Class Instances

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

    【讨论】:

      【解决方案2】:

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

      • 创建类时,必须先调用超类的构造函数。这会冒泡到Object class

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

      本示例中不涉及statics,除了技术monitor

      【讨论】:

        【解决方案3】:

        不,bcinstance 变量。

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

        Sandwich.main(args);
        

        所以当你写的时候:

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

        ...这是错误的。只有静态变量被初始化 - 和平常一样。

        【讨论】:

        • 感谢乔恩的回答。这是我在 JLS 中读到的内容(它说所有类变量都已初始化,而不仅仅是静态变量):在我们接下来的示例中,Java 虚拟机仍在尝试执行类 Test 的 main 方法。仅当类已初始化时才允许这样做(第 12.4.1 节)。初始化包括按文本顺序执行类 Test 的任何类变量初始化程序和静态初始化程序。但在初始化 Test 之前,必须先初始化它的直接超类,以及它的直接超类的直接超类,以此类推。
        • “类变量”==“静态变量”。请参阅docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.12.3“类变量是在类声明(第 8.3.1.1 节)中使用关键字 static 声明的字段,或者在接口声明(第 9.3 节)中使用或不使用关键字 static。”
        • 对不起,我很困惑。如果“类变量”==“静态变量”,为什么会说“类变量初始化器和静态初始化器”?
        • 甚至在本书的前面,作者说“变量在任何方法被调用之前被初始化——甚至是构造函数”,这里的例子中没有静态:linuxtopia.org/online_books/programming_books/thinking_in_java/…
        • @Jin:那是在调用构造函数的上下文中。
        猜你喜欢
        • 1970-01-01
        • 2015-04-02
        • 1970-01-01
        • 2017-08-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-12-22
        相关资源
        最近更新 更多