14

我正在学习“类和接口的初始化”,它说“T 是一个顶级类,并且执行了一个词法嵌套在 T 中的断言语句。” 谁能告诉我“T 是一个顶级类,并且执行了一个词法嵌套在 T 中的断言语句”是什么意思。举个例子?

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

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

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

4 回答 4

5

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

一个重要的观点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"));
    }
}

在上面的示例中,当b被初始化时,Java 保证在line(a)调用之前,断言被禁用(即 line(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"));
    }
}

即使-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() throws 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"));
    }
}

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

于 2013-07-23T07:51:58.640 回答
2

这是一个顶级课程:

class TopLevel {
   ...
}

这是一个断言语句:

assert( condition );

哪里condition是一些布尔表达式。

如果 A 出现在 B 定义的花括号内,则 A 在词法上嵌套在 B 中。例如,字段、方法、静态块在词法上嵌套在类定义中。语句在词法上嵌套在方法或静态块中。局部定义嵌套在方法或块中,它们本身也嵌套在方法中。

因此,在词法上嵌套在顶级类中的断言语句可以是:

class A {
    static {
        assert ( 2+2 == 4 );
    }
}
于 2013-07-23T08:42:01.090 回答
2

我知道我将如何阅读本规范,但 OpenJDK 1.7.0_40 的行为与指示不同,Oracle JDK 1.7.0_25 也没有。

顶级类是不嵌套在任何其他类中的类。断言语句可以出现在可执行代码中,即在方法、构造函数或静态初始化块中。大多数这些情况由其他项目处理:静态方法已经涵盖,其他方法以及构造函数属于所述类的对象的创建,静态初始化程序块是初始化过程的一部分,它是任何操作的结果的其他事件。

因此,我能想到的在不触发任何这些情况的情况下拥有词法嵌套语句的唯一方法是通过嵌套类。例如这样的:

class Outer {
    static {
        System.out.println("Outer initialized");
    }
    static class Nested {
        static void foo() {
            assert System.out == null;
        }
    }
}

但是,如果我Outer.Nested.foo()使用启用的断言运行,那么我会得到断言错误(因此语句被执行),而不是Outer initialized消息。因此,即使执行了词法嵌套的断言语句,顶级类也没有初始化。

要么我误解了这里的规范,要么提到的实现不遵循它。

至于基本原理:我认为这个要求的要点是启用和禁用断言是通过类的隐藏静态(和 iirc.final)字段实现的。因此,当 assert 语句被执行时,它必须检查该字段,因此必须初始化该字段,因此必须初始化类。但是在上面的代码中,相关的字段很可能是 的Outer.Nested,而不是它Outer自己的。Outer因此,此时不必初始化是有道理的。但除了上述结构之外,我想不出最后一条规则适用但其他规则都不适用的情况。

于 2013-07-23T08:59:21.040 回答
2

您已链接到JLS for Java 7 的第 12.4.1 节

在 java 错误JDK-8043189 “12.4.1:断言应该触发外部类的初始化吗?” 有一条评论解释说,列表的最后一个项目符号“T 是一个顶级类,并且执行了一个词法嵌套在 T 中的断言语句(第 14.10 节)”是完全错误的,它被错误地插入到JLS 回到了第 6 版,它一直呆到第 7 版只是因为没有人注意到它。

我发现该语句仍然存在于 JLS for Java 8 中,但它最终已从JLS for Java 9 的第 12.4.1 段中删除。

所以,底线是,不要试图从中找出任何意义,因为没有任何意义;这不是一个真实的陈述,而且从来都不是。

于 2017-12-27T23:20:15.247 回答