我很想知道JVM如何看到代码
public class StrTest {
static int i=10;
public static void main(String[] args) {
System.out.println(++i);
}
static{
String[] args = new String[10];
main(args);
System.out.println(++i);
StrTest test = new StrTest();
test.main(args);
}
}
在使用这种调用的任何框架中是否存在任何设计模式,其中应用程序通过静态块实例化或在main之前实现。
在新发现之后编辑
public class StrTest {
public static void main(String[] args) {
System.out.println(++i);
System.out.println("in main");
}
static {
System.out.println("in static block");
String[] args = new String[10];
main(args);
new StrTest().main(args);;
}
static int i = 10;
}
这是打印
in static block
1
in main
2
in main
11
in main
但是
public class StrTest {
public static void main(String[] args) {
System.out.println(++i);
System.out.println("in main");
}
static {
System.out.println(++i);//this line here is giving error Cannot
//reference a field before it is defined
System.out.println("in static block");
String[] args = new String[10];
main(args);
new StrTest().main(args);;
}
static int i = 10;
}
为什么然后在第一种情况下它将i初始化为0;
答案 0 :(得分:2)
据我所知。为什么?因为它是糟糕的想法。
静态初始化块很少有用 - 但它们绝对不是触发完整main()
的意思,而且上帝知道还有什么!
您会看到:这些块最有可能在 load 时执行。这意味着,如果发生这种情况,您几乎可以无控制。并且您不希望以复杂的行为为基础从某个随机时间点开始!
除此之外:你真的小心关于首先使用static
。这对新手程序员来说看起来很方便,但请放心:在现实世界中,你对使用它非常谨慎。因为它直接将事物耦合在一起(并且它杀死多态性 - 从而大大减少了“OOP”的价值)。而且你对使用static
init块更加小心。可接受的用例可能是:
public static final Map<Foo, Bar> SOME_KEYS = new HashMap<>();
static {
SOME_KEYS.put(someFoo, someBar);
SOME_KEYS.put(someOtherFoo, someOtherBar);
...
换句话说:您只能将它用于实际初始化变量,或更精确:常量。
答案 1 :(得分:1)
GhostCat清楚地解释了为什么你不应该这样做。我想补充一点,它不是惯用的,会使未来的代码维护更加困难。
现在从JVM看到技术:
StrTest
作为包含静态主StrTest.main
行而调用main()
StrTest.main
行而调用test.main()
,因为test
是StrTest
个对象
StrTest.main
它可以在这里工作,因为你在main中没有严重的操作,但结果是main被调用了好几次。在正常的程序中,这可能会导致灾难性的结果,只需要考虑一个消耗输入文件以擦除并生成输出文件的程序:在第二次迭代时,它将擦除其输出文件但不再输入...
你应该从中学到什么:
main
的类仍然是普通的Java类,并支持所有标准Java操作main
方法是常规静态方法,可以这样使用根据问题的编辑, Java语言规范Java SE 8版说:
静态初始值设定项和类变量初始值设定项按文本顺序执行,
在编辑的代码中,静态变量的初始化在静态块之后发生,对于i,静态块以默认值0执行,然后只有i
取得价值10
。在这里,请不要在实际代码中使用它...