2010-04-09 172 views
11

回到这不是有效的代码:静态初始化

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的原因是在那里结束施工。

感谢

+4

这些被称为静态构造函数,而不是静态构造函数。只是写这个来帮助搜索。 – Oak 2010-04-09 12:06:46

+0

@Oak:谢谢(15个字符) – 2010-04-09 12:18:41

回答

15

我认为原因是初始化器与字段初始化一起携带(并且在实例初始化器的情况下带有构造函数)。换句话说,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 

所以,如果你会在你的静态初始化器的某个地方添加一个“返回”,它也会有e防止z被计算。

+1

当我看到这些时,我正要写这些。还要注意,你可以在一个类中有多个静态初始化块。 – 2010-04-09 12:23:26

+0

真的很好的答案,橡树。它还说明了为什么在静态初始化器中突然完成被认为是非常糟糕的(正如Joe在评论中指出的那样)给出了编译时错误。 – jalopaba 2010-04-09 12:49:01

2

你应该返回?在静态初始化器中没有调用者,所以根据我的看法,返回没有任何意义。静态初始化器在类首次加载时执行。

10
  • 程序流程总是可以结构化而不需要return。 (在你的榜样将System.exit(0)else子句将达到预期的效果)

  • 在你真正需要它,你可以在一个静态方法移动代码,并从初始调用它:

static { 
    staticInit(); 
} 

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

请注意,这不是一个静态构造函数,这是一个静态初始化。没有任何建设。

+0

我知道你可以用简单的'else'来解决它。但我说这是一个非常愚蠢的例子。但它是真的! – 2010-04-09 12:05:10

+0

@Martijn Courteaux是的,我明白这一点。这就是为什么它在括号内,只是我的泛化的一个例子。 – Bozho 2010-04-09 12:08:00

1

JSL regarding static initializers

“这是一个静态初始化一个编译时错误能够与检查异常(§11.2)突然完成(§14.1,§15.6)这是一个编译期。如果静态初始化器无法正常完成(§14.21),则会出现时间错误。“

Abrupt completion(其中包括):“回归没有任何价值”,“与给定值返回”等

所以静态初始化return语句是“突然完成”,并产生一个编译期时间错误。

+1

JSL没有指定一个理由,但这是这个问题的关键。 – Oak 2010-04-09 12:11:16

+1

我刚刚发布了相同的东西,但我试图想:为什么“突然完成”一个静态初始化器如此糟糕,以致于它使它成为编译错误? – 2010-04-09 12:11:51

+0

@Oak:你说得对,没理由。规格有时像公理。 – jalopaba 2010-04-09 12:20:58

0

我知道静态初始化器的规则是每加载一次类的字节代码之后,在执行任何静态方法或实例化类中的第一个对象之前,它们都只执行一次。 JLS保证这个初始化已经完成。为了确保这一保证是真实的,JLS还规定代码不能突然终止(在另一个答案中明确给出)。

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

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

从这种情况下,无需重新启动JVM是,如果你使用的是ClassLoader S和可替代的类加载器与故障类和重建类或重新初始化器在不同的环境中恢复(也许是不同的系统属性)的唯一方法,但该计划必须为这种情况做好充分的准备。

0

我会重新排列语句,使其更简单/更短。如果if/else的两个分支都需要返回,将永远不会有好的情况。

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