13

这不是有效的代码:

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

6 回答 6

16

我认为原因是初始化程序与字段初始化(以及构造函数,在实例初始化程序的情况下)一起携带。换句话说,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 被计算。

于 2010-04-09T12:21:09.387 回答
11
  • 程序流程始终可以结构化,无需return. (在您的示例中放入System.exit(0)一个else子句将达到预期的结果)

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

.

static {
    staticInit();
}

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

请注意,这不是静态构造函数,而是静态初始化程序。没有任何东西被构建。

于 2010-04-09T11:57:47.107 回答
2

JSL 关于静态初始化器

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

突然完成(除其他外):“返回无值”、“返回给定值”等。

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

于 2010-04-09T12:09:29.340 回答
1

你应该返回什么?在静态初始化程序中没有调用者,所以就我看来,返回没有意义。首次加载类时会执行静态初始化程序。

于 2010-04-09T11:56:04.500 回答
0

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

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

如果任何静态初始化程序突然终止 - 这可能发生在 aRuntimeException中,则该类将处于无效状态。第一次,JVM 会抛出一个ExceptionInInitializeError(通知是一个Error,这意味着它被认为是内部故障)。从那时起,将无法使用该类 - 尝试调用静态方法或实例化对象,您将获得一个NoClassDefFoundError.

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

于 2010-04-09T13:02:20.310 回答
0

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

static { 
    if (!yesNo) 
       System.exit(0); // silently exiting a program is a bad idea!"
    System.out.println("Yes"); 
} 
于 2010-04-10T07:02:20.430 回答