Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/344.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 什么是;T是顶级类,执行嵌套在T中的assert语句;什么意思?_Java - Fatal编程技术网

Java 什么是;T是顶级类,执行嵌套在T中的assert语句;什么意思?

Java 什么是;T是顶级类,执行嵌套在T中的assert语句;什么意思?,java,Java,我正在学习“类和接口的初始化”,它说“T是一个顶级类,执行嵌套在T中的assert语句。” 有谁能告诉我什么是“T是顶级类,并且执行嵌套在T中的assert语句”是指一个示例 这句话来自,原文如下: 类或接口类型T将在第一次出现以下任一情况之前立即初始化: T是一个类,并且创建了T的一个实例 T是一个类,调用由T声明的静态方法 分配了一个由T声明的静态字段 使用T声明的静态字段,该字段不是常量变量(§4.12.4) T是一个顶级类,执行嵌套在T中的assert语句(§14.10) 我可以对此

我正在学习“类和接口的初始化”,它说“T是一个顶级类,执行嵌套在T中的assert语句。” 有谁能告诉我什么是“T是顶级类,并且执行嵌套在T中的assert语句”是指一个示例

这句话来自,原文如下:

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

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

我可以对此作部分解释。它指的是启用/禁用断言。断言由
-ea
vm参数启用

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"));
    }
}
在上面的例子中,当
b
被初始化时,Java保证在调用
行(a)
之前,断言被禁用(即,行(a)根本不被执行)。因为assert enable/disable是类初始化的一部分,所以在所示的语句中提到了它

之所以提到顶级类而不是其他所有类,原因是这样的。更详细的行为如下:

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
标志,它仍会抛出一个
断言异常
。发生的情况如下:

  • Q1.main被称为
  • Q1.main调用Baz.testassert
  • 因为Baz扩展了Bar,并且Bar未初始化,所以根据JLS,它尝试初始化Bar
  • 静态块的酒吧被称为。记住,assert语句是在其类完成初始化或调用assert之前启用的(先发生)。在本例中,由于
    条形图
    尚未完全初始化,因此在此阶段为
    true
  • 静态的
    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"));
        }
    }
    

    初始化良好时,这将打印
    断言禁用
    断言禁用<代码>栏初始化禁用类的
    断言
    ,因此对于
    Baz

    这是一个顶级类:

    class TopLevel {
       ...
    }
    
    这是一个断言语句:

    assert( condition );
    
    其中,
    条件
    是一些布尔表达式

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

    因此,词汇嵌套在顶级类中的assert语句可以是:

    class A {
        static {
            assert ( 2+2 == 4 );
        }
    }
    

    我知道该如何阅读该规范,但OpenJDK1.7.0_40的行为与所述不符,Oracle JDK1.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
    消息。因此,即使执行了词汇嵌套的assert语句,顶级类也没有初始化

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

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

    您已链接到

    在java bug中,有一条注释解释说列表的最后一个项目符号“T是顶级类,并且执行了按词汇嵌套在T中的assert语句(§14.10)”,这完全是错误的,它在版本6中被错误地插入到JLS中,并一直保留到版本7,因为没有人注意到它

    我发现