java文件报错不显示_java – 为什么我的程序不显示编译时错误final类变量未初始化?...

这篇博客探讨了Java中构造函数在遇到`throw`语句时如何中断执行,导致对象可能处于未完全初始化状态。静态最终字段的初始化在构造函数结束时变得重要,如果构造函数因异常而未完成,则可能导致静态字段未被正确赋值。博客还通过反编译代码展示了这一行为。此外,IntelliJ对于静态和非静态字段的处理差异也进行了讨论。
摘要由CSDN通过智能技术生成

有趣的是,代码将编译无论字段是否被标记为静态 – 并且在IntelliJ中,它将使用静态字段来投诉(但编译),而不是使用非静态字段来说一个字。

你是对的,JLS§8.1.3.2有关于[静态]最终字段的某些规则。然而,关于final字段的一些其他规则在这里起着很大的作用,来自Java语言规范§4.12.4 – 它指定了最终字段的编译语义。

但是在我们进入那个蜡球之前,我们需要确定当我们看到投掷时会发生什么 – 这是§14.18给我们的,强调我的:

A throw statement causes an exception (§11) to be thrown. The result is an immediate transfer of control (§11.3) that may exit multiple statements and multiple constructor, instance initializer, static initializer and field initializer evaluations, and method invocations until a try statement (§14.20) is found that catches the thrown value. If no such try statement is found, then execution of the thread (§17) that executed the throw is terminated (§11.3) after invocation of the uncaughtException method for the thread group to which the thread belongs.

在外行人的术语中 – 在运行时,如果我们遇到throws语句,它可以中断构造函数的执行(正式地,“突然完成”),导致对象不被构造或构造在不完整的状态。这可能是一个安全漏洞,这取决于平台和构造函数的部分完整性。

Declared final; never directly assigned to after object construction (JLS §17.5).

所以,我们有点腌渍 – 我们期望这在运行时,但不是在编译期间的行为。为什么IntelliJ在这个领域有静态时会引起轻微的轰动,但是当我没有静态时呢?

>正在抛出的表达式未选中或为null,

>你试图捕获异常,你正在捕捉它的类型,或者

>根据§8.4.6和§8.8.5,被抛出的表达式实际上可以被抛出。

因此,使用throws编译构造函数是合法的。它只是这样发生,在运行时,它将永远完成突然。

If a throw statement is contained in a constructor declaration, but its value is not caught by some try statement that contains it, then the class instance creation expression that invoked the constructor will complete abruptly because of the throw (§15.9.4).

现在,到那个空白的最后一个字段。有一个好奇的作品给他们 – 他们的任务只有在构造函数结束后才重要,强调他们。

A blank final instance variable must be definitely assigned (§16.9) at the end of every constructor (§8.8) of the class in which it is declared; otherwise a compile-time error occurs.

如果我们从未到达构造函数的结尾怎么办?

第一个程序:静态最终字段的正常实例化,反编译:

// class version 51.0 (51)

// access flags 0x21

public class com/stackoverflow/sandbox/DecompileThis {

// compiled from: DecompileThis.java

// access flags 0x1A

private final static I i = 10

// access flags 0x1

public ()V

L0

LINENUMBER 7 L0

ALOAD 0

INVOKESPECIAL java/lang/Object. ()V

L1

LINENUMBER 9 L1

RETURN //

L2

LOCALVARIABLE this Lcom/stackoverflow/sandbox/DecompileThis; L0 L2 0

MAXSTACK = 1

MAXLOCALS = 1

}

观察到我们实际上在成功调用我们的< init>之后调用RETURN指令。有意义,是完全合法的。

第二个程序:抛出构造函数和空白静态最终字段,反编译:

// class version 51.0 (51)

// access flags 0x21

public class com/stackoverflow/sandbox/DecompileThis {

// compiled from: DecompileThis.java

// access flags 0x1A

private final static I i

// access flags 0x1

public ()V throws java/lang/InstantiationException

L0

LINENUMBER 7 L0

ALOAD 0

INVOKESPECIAL java/lang/Object. ()V

L1

LINENUMBER 8 L1

NEW java/lang/InstantiationException

DUP

LDC "Nothin' doin'."

INVOKESPECIAL java/lang/InstantiationException. (Ljava/lang/String;)V

ATHROW //

L2

LOCALVARIABLE this Lcom/stackoverflow/sandbox/DecompileThis; L0 L2 0

MAXSTACK = 3

MAXLOCALS = 1

}

The rules of ATHROW表示引用被弹出,并且如果在那里有一个异常处理程序,它将包含处理异常的指令的地址。否则,它将从堆栈中删除。

我们从不显式返回,因此意味着我们从不完成对象的构造。因此,对象可以被认为处于一个初始化的半初始化状态,即所有语句都是可达的。

在静态字段的情况下,由于它不被认为是一个实例变量,而是一个类变量,这种调用看起来是错误的。这可能值得提出一个bug。

回想一下,它在上下文中确实有意义,因为Java中的以下声明是合法的,并且方法体与构造函数体是一致的:

public boolean trueOrDie(int val) {

if(val > 0) {

return true;

} else {

throw new IllegalStateException("Non-natural number!?");

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值