即使在 Java 中初始化子类后,静态变量的值也不会更改

当我使用( 作为子类)调用静态变量时,静态块不会执行,并且 的值不会更新。yChecks.yChecksy

class Par {
    static int y = 4;
}

class Checks extends Par {
    static {
        y = 5;
    }
}

public class Check {
    public static void main(String args[]) {
        System.out.println(Checks.y); // here printing 4
    }
}

由于静态在所有子类之间共享,因此应该更新该值。

这背后的原因可能是什么?


答案 1

该字段不是由类 声明的。yChecks

读取静态字段不会触发引用的类 () 的初始化,除非该类是声明该字段的类(请参阅下面的 JLS 引用)。在此示例中,即使通过 访问,也只会触发初始化,因为是声明 的类。ChecksyChecksParPary

换句话说,从某种意义上说,该类不在运行时使用。Checks

这也许可以说明为什么通过子类访问成员是错误的,这会导致编译时警告。static


规范中有一个简单的解释:

12.4.1. 初始化发生时

类或接口类型 T 将在首次出现以下任一项之前立即初始化:

  • T 是一个类,并创建了 T 的一个实例。

  • 调用由 T 声明的静态方法。

  • 分配由 T 声明的静态字段。

  • 使用 T 声明的静态字段,并且该字段不是常量变量 (§4.12.4)。

  • T 是顶级类 (§7.6),执行词法嵌套在 T (§8.1.3) 中的断言语句 (§14.10)。
    ...
    对静态字段 (§8.3.1.1) 的引用仅会导致初始化实际声明它的类或接口,即使它可能通过子类、子接口或实现接口的类的名称来引用。

最后一个注释解释了子类未初始化的原因。


答案 2

来自 JLS 12.4.1

类或接口类型 T 将在首次出现以下任一项之前立即初始化:

  • T 是一个类,并创建了 T 的一个实例。
  • T 是一个类,调用由 T 声明的静态方法。
  • 分配由 T 声明的静态字段。
  • 使用 T 声明的静态字段,并且该字段不是常量变量 (§4.12.4)。
  • T 是顶级类 (§7.6),并执行词法嵌套在 T (§8.1.3) 中的断言语句 (§14.10)。

由于 y 未在检查中声明,因此不满足上述任何条件。

说明此行为的另一种方法:

class par {
    static int y = 4;
    static {
        System.out.println("static constructor of par");
    }
}

class checks extends par {
    static int x = 6;
    static {
        System.out.println("checks static constructor");
        y = 5;
    }
}

public class check{
    public static void main(String args[]){
        System.out.println(checks.y);
        System.out.println(checks.x);
        System.out.println(checks.y);
    }
}

输出

static constructor of par
4
checks static constructor
6
5

因此,在调用满足第二个规则的函数后,将调用静态构造函数。checks.x


推荐