静态字段的有趣功能。 StackOverflow异常

时间:2009-05-19 15:58:09

标签: oop

您有任何想法,为什么以下代码:

public class A
{
    public static int i = B.i + 1;
}

public class B 
{
    public static int i = A.i + 1;
}

有:

        int aa = A.i;
        int bb = B.i;

说aa = 2(!!!)和bb = 1.

我脑子里有一个堆叠溢出! 据我所知,递归在静态方法上停止,但为什么呢? 如果你将int i重新编写为getter(为了调试并理解它为什么会这样工作),你会得到堆栈溢出异常。

3 个答案:

答案 0 :(得分:6)

毫无疑问,执行正在发生:

首先运行B.i静态初始值设定项,然后设置B.i = A.i + 1。由于A.i尚未初始化,A.i等于default(int),即0B.i获取值1

A.i静态初始化程序运行第二个,并设置A.i = B.i + 1 = 2

由于静态初始化程序以未定义的顺序运行,因此每次运行时,您可能会发现其他字段为2,或者当您对代码进行其他结构更改时,它们会切换。但是,应始终为2,其中一个应始终为1

P.S。这与多态性无关。

编辑:为了进一步了解静态初始化器和构造函数的时序,您可能需要检查this relevant portion of the C# specification.

答案 1 :(得分:4)

字段不像属性getter。它只存储数据,而不是任何操作。实际上,初始化将被移动到另一个方法(静态构造函数,.cctor),它将初始化类中的静态变量。

一开始,两者都将等于0.在您第一次访问A.i之前,类.cctor的方法A会运行。它首次尝试访问B.i,这将导致执行类B的静态构造函数。 .cctor的{​​{1}}将尝试访问B,但由于这不是第一次访问字段,A.i的静态构造函数再跑了。它只获取A的当前值,该值仍为0.因此,A完成执行并且控制权返回B.i时,B..cctor将等于1。它会看到值A..cctor并将其加1并将其存储在B.i中。因此,A.i将等于2(1 + 1),A.i将等于1.

唯一的保证是静态构造函数在之前被称为,访问该类的任何静态成员。

答案 2 :(得分:1)

这是正在发生的事情。

  • 第一次访问A.
  • A.i创建的值为0.
  • A的静态初始化程序运行。
  • 首次访问B.
  • A.i被访问。它目前的价值为0。
  • B.i设置为1. A.i设置为2.

非常重要的一点是,静态属性被初始化为默认值,然后然后静态初始化程序运行。

就个人而言,我尽可能避免静态初始化,静态和其他。有太多的陷阱。