在静态初始化器中返回

这不是有效的代码:

public class MyClass { private static boolean yesNo = false; static { if (yesNo) { System.out.println("Yes"); return; // The return statement is the problem } System.exit(0); } } 

这是一个愚蠢的例子,但在静态类构造函数中我们无法return; 。 为什么? 这有充分的理由吗? 有人知道更多关于此的事情吗?

所以我应该return的原因是结束那里的建设。

谢谢

我认为原因是初始化器与字段初始化一起进行(对于构造函数,在实例初始化器的情况下)。 换句话说,JVM只识别一个地方来初始化静态字段,因此所有初始化 – 无论是否在块中 – 都必须在那里完成。

所以,例如,当你写一个类时:

 class A { static int x = 3; static { y = x * x; } static int z = x * x; } 

然后它实际上好像你写了:

 class A { static int x, y, z; static { x = 3; y = x * x; z = x * x; } } 

如果你看一下反汇编,就会证实这一点:

 static {}; Code: 0: iconst_3 1: putstatic #5; //Field x:I 4: getstatic #5; //Field x:I 7: getstatic #5; //Field x:I 10: imul 11: putstatic #3; //Field y:I 14: getstatic #5; //Field x:I 17: getstatic #5; //Field x:I 20: imul 21: putstatic #6; //Field z:I 24: return 

因此,如果您在静态初始化程序的中间某处添加了“返回”,那么它也会阻止计算z。

  • 程序流程总是可以构建成不需要return 。 (在您的示例中,将System.exit(0)放入else子句中将获得所需的结果)

  • 你真的需要它,你可以用静态方法移动代码并从初始化程序调用它:

 static { staticInit(); } private static void staticInit() { if (yesNo) { System.out.println("Yes"); return; } System.exit(0); } 

请注意,这不是静态构造函数 ,而是静态初始化程序 。 什么都没有建成。

你应该回到什么地方? 在静态初始化器中没有调用者,所以就我看来,返回没有意义。 第一次加载类时会执行静态初始值设定项。

从JSL关于静态初始化器 :

“静态初始化程序能够突然完成(第14.1节,第15.6节)并且检查exception(第11.2节)是一个编译时错误。如果静态初始化程序无法正常完成,则是编译时错误(§ 14.21)。”

突然完成 (以及其他):“没有价值的回报”,“给定价值的回报”等。

因此,静态初始化程序中的return语句是“突然完成”并产生编译时错误。

我理解静态初始化程序的规则是它们只在加载类字节代码之后和执行任何静态方法或从类中实例化第一个对象之前执行一次。 JLS保证此初始化已完成。 为确保此保证为真,JLS还指定代码不能突然终止(在另一个答案中明确说明)。

注意,可以在不初始化的情况下加载字节码; 请参阅Class.forName(String,boolean,ClassLoader)方法。 如果boolean参数为false那么这将加载类但不初始化它。 程序员仍然可以做一些反思,以便在没有初始化的情况下仍然发现有关该类的信息。 但是,一旦尝试通过调用静态方法或实例化实例来直接使用该类,则JVM将首先进行初始化。

如果任何静态初始化程序突然终止 – 这可能发生在RuntimeException ,则该类将保持无效状态。 第一次,JVM将抛出ExceptionInInitializeError (注意这是一个Error ,这意味着它被认为是内部故障)。 从那时起,将无法使用该类 – 尝试调用静态方法或实例化对象,而不是获取NoClassDefFoundError

在不重新启动JVM的情况下从这种情况中恢复的唯一方法是,如果您正在使用ClassLoader并且可以使用失败的类替换类加载器并在不同的环境(可能是不同的系统属性)中重建类或重新初始化程序,但程序必须然后为这种情况做好充分准备。

我会重新排序声明,使其更简单/更短。 永远不会有一个好的情况,if / else的两个分支都需要返回。

 static { if (!yesNo) System.exit(0); // silently exiting a program is a bad idea!" System.out.println("Yes"); }