为什么java静态变量没有更新?

为什么java静态变量没有更新?,java,static,Java,Static,我有一个名为Color的类,其中有三个静态对象(用同一个类本身实例化)和一个int类型(称为I)变量。当我运行这个类时,“I”变量在构造函数中是递增的,但它没有在内存中持久化,请在下面解释这个代码 package test; public class Color { public static Color RED = new Color(); public static final Color BLUE = new Color(); public static f

我有一个名为Color的类,其中有三个静态对象(用同一个类本身实例化)和一个int类型(称为I)变量。当我运行这个类时,“I”变量在构造函数中是递增的,但它没有在内存中持久化,请在下面解释这个代码

package test;
public class Color
{
     public static  Color RED = new Color();
     public static final Color BLUE = new Color();
     public static final Color GREEN = new Color();
     static int i=0;

     Color(){
         System.out.println("Incrementing 'i'  here  "+(++i));
     }

     public static void main(String[] args) {
         System.out.println("The 'i' variable is not incremented here, it still shows '0' ,  'i' is: "+ Color.i );  // line 14 
        Color x = new Color();
        System.out.println(x.i);
    }
}
结果如下:

Incrementing 'i'  here  1
Incrementing 'i'  here  2
Incrementing 'i'  here  3
The 'i' variable is not incremented here, it still shows '0' ,  'i' is: 0
Incrementing 'i'  here  1
1

加载并链接类时,其
静态
字段均初始化为默认值。完成后,静态字段初始值设定项将按照它们在文件中出现的顺序执行,从而完成类的初始化。所有这些都发生在该类中定义的任何代码执行之前。所以这里发生的是:

  • 红色
    绿色
    蓝色
    i
    初始化为默认值(
    颜色
    字段为
    i
    字段为0)。请注意,这与任何初始值设定项无关
  • 执行字段
    RED
    RED=new Color()
    )的初始值设定项。作为副作用,
    i
    增加到1
  • 执行字段
    BLUE
    的初始值设定项,并将
    i
    增加到2
  • 执行字段
    GREEN
    的初始值设定项,并将
    i
    增加到3
  • 执行
    static
    字段
    i
    的初始值设定项,并将
    i
    赋值为0
  • main()
    开始执行时,执行
    main()
    方法并生成与
    i
    为0一致的结果
  • 你可以在和中阅读所有这些血淋淋的细节

    只需将
    i
    的声明移到
    Color
    字段之前,即可获得预期的输出:

     static int i=0;
     public static  Color RED = new Color();
     public static final Color BLUE = new Color();
     public static final Color GREEN = new Color();
    
    那么输出将是:

    在此处递增“i”1
    在这里递增'i'2
    在这里递增'i'3
    “i”变量在这里没有递增,它仍然显示“0”,“i”是:3
    在这里递增'i'4
    四,


    请注意,
    最终
    修饰符对此处的初始化顺序没有影响,因为根据JLS中该术语的定义,
    绿色
    蓝色
    不是“常量变量”。常量变量(一个不幸的词对)是一个原语或
    字符串
    变量,它既被声明为
    final
    ,又被初始化为常量表达式。在这种情况下,
    new Color()
    不是常量表达式,
    Color
    不是常量变量的合适类型。例如,请参见。

    类初始化从上到下进行。初始化颜色时,我们创建一个新颜色。为了创建新颜色,我们还必须初始化颜色。这称为递归初始化,系统所做的只是忽略递归初始化并执行
    newcolor()
    。此类初始值设定项按以下顺序自上而下执行

  • 公共静态颜色红色=新颜色()将静态变量i设置为1

  • 公共静态最终颜色蓝色=新颜色()这将静态变量i增加到2

  • 公共静态最终颜色绿色=新颜色()这将静态变量i增加到3

  • static int i=0将静态变量i设置回零

  • 现在,当主线程运行时,它看到静态变量为0,并递增为1


    作为一个反例,尝试将
    静态整数i=0
    替换为
    静态整数i=新整数(0)。
    。这将抛出一个
    NullPointerException
    。这是因为在类初始化时,
    public static Color RED=new Color()
    执行时,它会将i视为null,因为那时我还没有初始化,导致
    NullPointerException

    说到JLS的第12章,如果我正确阅读了12.4.1,将不会
    蓝色
    绿色
    红色
    之前初始化,因为它们是
    最终的
    ?@Powerlord否,final不是常数。只有字符串和原语可以是常量,这需要遵守一些规则。此外,常量与所有其他字段一样被初始化,只是它们的值可以在初始化之前使用,因为它在编译时就已经知道了,所以编译器用它的已知值替换了变量access。@Powerlord-你说得对。我没有注意到这两个字段上的
    final
    修饰符。我将更新我的答案以反映这一点。@kumesana-这一分析是错误的。首次加载类时,所有静态字段(包括
    final
    字段)都将初始化为其默认值。编译器不知道将由
    new Color()
    返回的对象的地址;这是在初始化器执行时确定的,它发生在运行时,在类的初始化过程的后期(但仍然在
    main()
    开始执行之前)。@TedHopp final或non final不重要,也不会更改初始化顺序。既然你的答案假装正确,你的答案就错了。顺便说一句,你可以试一下。我不知道这个想法从何而来,但我认为它来自常数的存在,常数是一个重叠但不同的主题。