以静态方式创建对象


68

谁能解释Java如何执行此代码?我的意思是执行每个语句的顺序。

public class Foo
{
    boolean flag = sFlag;
    static Foo foo = new Foo();
    static boolean sFlag = true;

    public static void main(String[] args)
    {
        System.out.println(foo.flag);
    }
}

输出:

false

4
我们是人类,而不是计算机。我们是否应该尝试使代码更简单明了,而不是使用这些技巧或陷阱等等?
唐李

1
+1,因为这不是一个难题,但却是一个很好的问题,我相信它将帮助其他人更好地理解语言,尤其是静态修饰符。@JonSkeet针对一个非常重要但常常被低估的主题给出了非常有用的答案。
jorey 2012年

1
当人们使用“ Foo”时,我不喜欢它。使用真实术语:/
contactmatt 2012年

Answers:


104
  • 类初始化开始。最初foo为null,sFlag为false
  • 第一个静态变量初始值设定项(foo)运行:
    • Foo创建了一个新实例
    • 用于flag执行的实例变量初始值设定项-当前sFlag为false,因此值为flagfalse
  • 执行第二个静态变量初始化器(sFlag),将值设置为true
  • 类初始化完成
  • main运行,打印出foo.flag,这是错误的

请注意,如果sFlag声明为final,则将其视为编译时常量,此时,对其的所有引用基本上都将内联到true,因此foo.flag也是如此。


在类中定义变量的顺序是否重要?即是否flag在之后定义sflag
纳文

@Naveen恕我直言,我不这么认为。静态变量将首先被初始化。
Eng.Fouad 2012年

1
@Naveen:因为如果顺序事项sFlag之前被宣布foo,这将关系-但sFlagflag顺序无关紧要。
乔恩·斯基特

5
静态成员按照声明的顺序初始化。如果在创建实例之前声明sFlag,则输出为true。
德罗纳

1
@ClintHui:编译时常量在引用常量字段的任何地方都使用其常量值,而不是实际访问该字段...因此,字段尚未真正设置为其值也没关系。
乔恩·斯基特

12

foo 在类的静态初始化期间以及sFlag初始化之前被实例化,并且布尔值的默认值为false。

  1. 该类已加载
  2. Foo初始化为实例

    2.a将实例成员标志初始化为sFlag的值(false默认情况下)

  3. sFlag初始化为true

有关更多详细信息,请参考JLS§12.4


5

当类被加载,sFlag并且foo字段被初始化但foo首先被初始化时!
字段flagsFlag均为布尔值,不能为null,因此默认情况下sFlag为false,foo并且在初始化时仍为false 。flag = sFlag在这flag是假的之后。就是这样


2

初始化操作的一般顺序是(在加载类之后和首次使用之前):

  1. 静态(类)代码块在代码中的显示顺序,
  2. 目标代码块按其出现在代码中的顺序排列(初始化块和分配)。
  3. 建设者

当然,我没有将构造函数和函数体称为上面的代码块

我不知道final static领域。看起来它们遵循static字段规则,并且尽管在注释之前已在编译步骤对其进行了初始化,但它们在声明之前无法被引用。如果在编译错误之前引用了它们:

Example.java:8: illegal forward reference
        System.err.println("1st static block j=" + j);

也许final static可以将字段初始化并编译到类文件中,但这不是一般规则,并且在声明之前仍不能引用它们。

检查初始化顺序的示例代码:

class Example {    

    final static int j = 5;

    {
        System.err.println("1st initializer j=" + j);
    }

    static {
        System.err.println("1st static block j=" + j);
    }

    static {
        System.err.println("2nd static block j=" + j);
    }

    final static java.math.BigInteger i = new java.math.BigInteger("1") {    
        {
            System.err.println("final static anonymous class initializer");
        }
    };

    Example() {
        System.err.println("Constructor");
    }

    static {
        System.err.println("3nd static block j=" + j);
    }

    {
        System.err.println("2nd initializer");
    }

    public static void main(String[] args) {
        System.err.println("The main beginning.");
        Example ex = new Example();
        System.err.println("The main end.");
    } 
}

上面的代码片段打印:

1st static block j=5
2nd static block j=5
final static anonymous class initializer
3nd static block j=5
The main beginning.
1st initializer j=5
2nd initializer
Constructor
The main end.


1

首先,静态字段应该运行,并且首先是内联!因此,在第4行,然后在第5行将运行,因此首先将foo初始化,并且我们知道布尔变量默认情况下被初始化为false,因此首先在foo初始化时,flag字段为sflag,即为false,然后sfalsg变为true不会更改标志(没有关系),然后在最后一次主运行并打印错误的falg !!!希望对您有用!成功的

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.