当前位置: 首页 > 知识库问答 >
问题:

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

岳阳文
2023-03-14

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

这句话来自JLS,原文如下:

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

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

共有3个答案

谷彦君
2023-03-14

我知道我将如何阅读这个规范,但是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;
        }
    }
}

但是如果我运行外部。嵌套的。foo()启用断言后,我会得到断言错误(因此语句被执行),但不会得到外部初始化的消息。因此,即使执行了词汇嵌套的assert语句,顶级类也没有初始化。

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

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

柳逸春
2023-03-14

这是一个顶级的类:

class TopLevel {
   ...
}

这是一个断言语句:

assert( condition );

其中条件是一些布尔表达式。

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

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

class A {
    static {
        assert ( 2+2 == 4 );
    }
}
文志学
2023-03-14

我可以对此作部分解释。它指的是启用/禁用断言。断言由-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"));
    }
}

在上述示例中,当初始化b时,Java保证在调用(a)行之前,断言被禁用(即(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标志,它仍会抛出一个 断言异常。发生的情况如下:

  1. 问题1。main被称为
  2. 问题1。主叫巴兹。遗嘱
  3. 因为Baz扩展了Bar并且Bar未初始化,所以根据JLS,它尝试初始化Bar
  4. 静态块的酒吧被称为。记住,assert语句是在其类完成初始化或调用assert之前启用的(先发生)。在本例中,由于条形图仍未完全初始化,因此在此阶段为
  5. 静态的Bar调用Baz。testAsserts()。断言仍然处于启用状态(请记住,禁用断言与类初始化有关,而Bar仍然没有完全初始化)。现在,巴兹。testAsserts()抛出断言异常

上面是一个环孔。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

 类似资料:
  • 问题内容: 我在尝试找到答案时遇到了麻烦。我想知道语法和含义。我已经找到了一些信息,但是我不太了解使用该语法的目的。我正在寻找它的功能以及何时/为什么使用它的解释。 一个被使用的例子: 问题答案: 在函数调用的上下文中,将命名参数设置为空字符串。见函数; 是打印时多个值之间使用的分隔符。默认值是空格(),此函数调用可确保格式的浮点值和格式的浮点值之间没有空格。 比较以下三个调用的输出以查看区别 更

  • 问题内容: 这样的方法声明有什么区别: 还有这个: 我的看法是,他们两个都指定传入的对象 必须 是type的子类,那么在这种情况下为什么还要烦恼泛型呢? 问题答案: 在您的情况下,差别不大。 但是请考虑以下几点: 在这种情况下,您可以通过以下方式调用该方法: 如果您使用 您将只能执行以下操作:

  • 在超过时间限制的各种代码中,通过使用while(t-->0)而不是while(t--)代码成功运行。我不知道while(t-->0),我在codechef示例解决方案的某个地方读到了它。

  • 问题内容: 我在某些插入T-SQL查询中看到前缀N。在表中插入值之前,许多人已经使用过。 我进行了搜索,但是在将任何字符串插入表之前,我无法理解包括的目的是什么。 此“ N”前缀起什么作用?何时使用? 问题答案: 它声明字符串为数据类型,而不是 您可能已经看到了Transact- SQL代码,该代码使用N前缀传递字符串。这表示后面的字符串是Unicode(N实际上代表本国语言字符集)。这意味着您要

  • 在每个print语句之前使用扫描器解决了这个问题,但我想要一个好的编程方法来解决这个问题。

  • 问题内容: 我正在寻找有关Google Go语言的信息。在“ A Go of Go”中,他们具有以下代码: 但是什么和 意味着什么呢? 您可以在http://tour.golang.org/#14上查看所有代码 问题答案: 它们是按位移位运算符。表示 x ×2 y ,而表示 x ×2 -y 或等效地x÷2 y。这些运算符通常用于操作值的二进制表示形式,就像十进制的10的幂一样,乘或除以2的幂分别具