问题
This isn't valid code:
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);
}
}
This is a stupid example, but in a static class constructor we can't return;
.
Why? Are there good reasons for this? Does someone know something more about this?
So the reason why I should do return
is to end constructing there.
Thanks
回答1:
I think the reason is that initializers are carried together with field initializations (and with constructors, in the case of instance initializers). In other words, the JVM only recognizes one place to initialize static fields, and thus all initializations - whether in blocks or not - must be done there.
So, for example, when you write a class:
class A {
static int x = 3;
static {
y = x * x;
}
static int z = x * x;
}
Then it's actually as if you've written:
class A {
static int x, y, z;
static {
x = 3;
y = x * x;
z = x * x;
}
}
This is confirmed if you look at the disassembly:
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
So if you would have added a "return" somewhere in the middle of your static initializer it would also have prevented z from being calculated.
回答2:
the program flow can always be structured to go without the need for
return
. (In your example puttingSystem.exit(0)
in anelse
clause would achieve the desired result)in you really need it, you can move the code in a static method and call it from the initializer:
.
static {
staticInit();
}
private static void staticInit() {
if (yesNo) {
System.out.println("Yes");
return;
}
System.exit(0);
}
Note that this is not a static constructor, it's a static initializer. Nothing gets constructed.
回答3:
What should you return to? In a static initializer there is no caller, so a return doesn't make sense as far as I see it. Static initializers are executed when the class is loaded for the first time.
回答4:
From JSL regarding static initializers:
"It is a compile-time error for a static initializer to be able to complete abruptly (§14.1, §15.6) with a checked exception (§11.2). It is a compile-time error if a static initializer cannot complete normally (§14.21)."
Abrupt completion (among others): "return with no value", "return with a given value", etc.
So a return statement in a static initializer is an "abrupt completion" and produces a compile-time error.
回答5:
I understand that the rule for static initializers is that they are only every executed one time, after the class byte-code is loaded and before executing any static method or instantiating the first object from the class. The JLS guarantees that this initialization will have been completed. To ensure that this guarantee is true, the JLS also specifies that the code cannot have been abruptly terminated (as given clearly in another answer).
Note that it is possible to load byte-code without initializing it; see Class.forName(String, boolean, ClassLoader) method. If the boolean
parameter is false
then this will load the class but not initialize it. The programmer can still do some reflection to discover information about that class still without it being initialized. However, once you attempt to use the class directly by calling a static method or instantiating an instance, then the JVM will proceed to initialize it first.
If any of the static initializers do abruptly terminate - which can happen with a RuntimeException
, the class will be left in an invalid state. The first time, the JVM will throw an ExceptionInInitializeError
(notice that is an Error
which means it is considered an internal failure). From that point on it will not be possible to use the class - attempting to call a static method or instantiating an object you will instead get a NoClassDefFoundError
.
The only way to recover from this situation without restarting the JVM is if you are using ClassLoader
s and can replace the class loader with the failed class and rebuild the class or reinitializer in a different environment (perhaps different system properties), but the program must then be well prepared for this kind of situation.
回答6:
I would reorder the statement, making it simpler/shorter. There will never be a good case where both branches of if/else need a return.
static {
if (!yesNo)
System.exit(0); // silently exiting a program is a bad idea!"
System.out.println("Yes");
}
来源:https://stackoverflow.com/questions/2607112/returning-in-a-static-initializer