从静态块调用Java Main方法

时间:2018-02-21 10:24:49

标签: java static

我很想知道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;

2 个答案:

答案 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看到技术

  • 加载可执行jar文件
  • 找到类StrTest作为包含静态主
  • 启动
  • 类加载器加载类并执行静态初始化:
    • 初始化静态变量i
    • 执行静态init块:
    • StrTest.main行而调用main()
      • 增加并打印i
    • 增加并打印i
    • StrTest.main行而调用test.main(),因为testStrTest个对象
      • 增加并打印i
  • 在JVM作为程序启动的一部分调用main之前发生的所有事情!...
  • JVM通常使用实际的命令行参数作为参数调用StrTest.main
    • 增加并打印i

它可以在这里工作,因为你在main中没有严重的操作,但结果是main被调用了好几次。在正常的程序中,这可能会导致灾难性的结果,只需要考虑一个消耗输入文件以擦除并生成输出文件的程序:在第二次迭代时,它将擦除其输出文件但不再输入...

你应该从中学到什么:

  • 包含main的类仍然是普通的Java类,并支持所有标准Java操作
  • main方法是常规静态方法,可以这样使用
  • 你不应该用正常的代码

根据问题的编辑, Java语言规范Java SE 8版说:

  

静态初始值设定项和类变量初始值设定项按文本顺序执行,

在编辑的代码中,静态变量的初始化在静态块之后发生,对于i,静态块以默认值0执行,然后只有i取得价值10。在这里,请不要在实际代码中使用它...