什么是"T是顶级类,并且在词典中嵌套在T中的断言语句被执行." 意思?

hua*_*hui 13 java

我正在学习"类和接口的初始化",它说"T是一个顶级类,并且在T中执行词法嵌套的断言语句." 任何人都可以告诉我"T是一个顶级类,并且执行一个词法嵌套在T中的断言语句." 举个例子?

这句话来自JLS,原文是这样的:

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

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

Jat*_*tin 5

我可以给它一个部分解释.它指的是启用/禁用断言.声明由-eavm参数启用.

关键assert是:

在其类完成初始化之前执行的assert语句已启用.

假设-ea未给出,您运行以下代码:

 public class Q1 {
    public static void main(String[] args) {
        Bar b = new Bar();
    }
}
class Bar {
    static {
        boolean enabled = false;
        assert  enabled = false; //line(a)
        System.out.println("Asserts " + 
               (enabled ? "enabled" : "disabled"));
        System.out.println("as");
        Baz.testAsserts();
    }
}
class Baz extends Bar {
    static void testAsserts() {
        boolean enabled = false;
        assert  enabled = false;
        System.out.println("Asserts " + 
               (enabled ? "enabled" : "disabled"));
    }
}
Run Code Online (Sandbox Code Playgroud)

在上面的示例中,当b初始化时,Java保证在line(a)调用before之前,断言被禁用(即,行(a)根本不被执行).因为断言启用/禁用是类初始化的一部分,因此在您显示的声明中提到它.

原因,为什么提到顶级课而不是其他所有课都是这个.这里有更详细的行为:

public class Q1 {
    public static void main(String[] args) {
        Baz.testAsserts(); 
        // Will execute after Baz is initialized.
    }
}
class Bar {
    static {
        Baz.testAsserts();
        // Will execute before Baz is initialized!
    }
}
class Baz extends Bar {
    static void testAsserts() {
        boolean enabled = false;
        assert  enabled = false;
        System.out.println("Asserts " + 
               (enabled ? "enabled" : "disabled"));
    }
}
Run Code Online (Sandbox Code Playgroud)

甚至-ea没有使用旗帜,它仍然会抛出AssertionException.这是发生的事情:

  1. Q1.main被调用
  2. Q1.main调用Baz.testAsserts.
  3. 因为Baz扩展了Bar和Bar没有初始化,所以根据JLS它会尝试初始化Bar
  4. 调用Bar的静态块.记住assert语句在其类完成初始化或调用assert之前启用(首先发生).在这种情况下,true在这个阶段Bar仍未完全初始化
  5. Bar电话静态Baz.testAsserts().断言仍然被启用(记得禁用断言与类初始化有关,而Bar仍未完全初始化).现在Baz.testAsserts()抛出AssertionException.

上面是一个环孔.JLS只保证在执行assert顶级类中的任何一个之前,它将禁用/启用(如同给定的任何vm参数)它.但如果它不是顶级类,那么行为取决于顶级类的初始化.要解释这一点,请看:

class Bar {
    static {
        //Baz.testAsserts();
        boolean enabled = false;
        assert  enabled = false;
        System.out.println("Asserts " + 
               (enabled ? "enabled" : "disabled"));
        // Will execute before Baz is initialized!
    }
}
class Baz extends Bar {
    static void testAsserts() {
        boolean enabled = false;
        assert  enabled = false;
        System.out.println("Asserts " + 
               (enabled ? "enabled" : "disabled"));
    }
}
Run Code Online (Sandbox Code Playgroud)

这打印Asserts disabled Asserts disabledBar很好初始化.Bar初始化禁用assert该类,因此禁用Baz.

  • 虽然你引用了 JLS 的很多东西,但我不明白你的意思。您谈到了在初始化期间启用断言语句的时间点。最初的问题是关于断言语句*触发*初始化的。此外,据我所知,您的班级`Baz` 是顶级的,因为它不是嵌套的。继承在原始问题中不起作用。所以虽然你写的大部分内容都是正确的,但我看不出它是如何回答问题的。我知道你自己说过这是部分答案,但我很惊讶它已经被接受了。 (2认同)