静态变量在初始化对象本身之前为空

Static Variables are null before initializing the object itself

今天我 运行 关注以下问题:

我有三个 classes,(superclass) A,(subclass) B 和我的 Main class。以下是该结构的一些代码示例:

public abstract class A {
    
    public static String testValue;

    public static boolean valueSet() {
        return testValue != null;
    }

}
public class B extends A {
    
    static {
        System.out.println("TEST");
        testValue = "foo";
    }
    
}
public class Main {

    public static void main(String[] args) {
        System.out.println(B.testValue);
        System.out.println(B.valueSet());
        System.out.println(new B());
        System.out.println(B.testValue);
        System.out.println(B.valueSet());
    }

}

我希望得到以下输出:

foo
true
foo
true

但是,代码输出的是:

null
false
foo
true

我的最终目标是在每个subclass中将testValue设置为某个值,并在superclass中只实现一次检查功能。它必须是静态的,因为它应该只检查字符串与 A 类型的对象的兼容性。将使用方法定义为 public static abstract 是不可能的,因为我已经 read,并且无法抽象值,所以我也不能使用它。我希望代码尽可能简单,而不是为每个 subclass.

重新实现检查

感谢您的帮助或提示!

您没有在调用 new B() 之前初始化 class B(在您的代码示例中)!

首先,您有点误用 Java 通过子类型访问静态变量的可能性。没有B.testValue,只有A.testValue。编译器实际上取代了它。对B.valueSet()的调用也是如此。只有 A.valueSet().

所以,你写

System.out.println(B.testValue);
System.out.println(B.valueSet());

但编译器将其替换为

System.out.println(A.testValue);
System.out.println(A.valueSet());

因为静态成员确实属于声明它们的 class。

对您的代码稍作改动表明:

public class B extends A {
    public static String foo = "foo"; // Note the new static variable here.

    static {
        System.out.println("TEST");
        testValue = "foo";
    }
}

public class Main {

    public static void main(String[] args) {
        System.out.println(B.foo); // Note the new access here.
        System.out.println(B.testValue);
        System.out.println(B.valueSet());
        System.out.println(new B());
        System.out.println(B.testValue);
        System.out.println(B.valueSet());
    }

}

现在可以正确打印

TEST
foo
foo
true
B@2a139a55
foo
true

因为现在你的 class B 首先被初始化了。

提示:访问静态成员时应始终使用声明 class 作为引用。

正如问题下方的评论所暗示的那样,这个问题没有任何问题;但是,您的代码无法复制,因为它会绝不会,打印您所说的任何内容。

一般来说,使用调试器并逐步查看执行流程总是一个好主意。

让我们看看发生了什么:

  1. System.out.println(B.testValue);class A 交互,因为 B 没有静态 testValue 成员,但 A 有(是的,静态成员是可访问的在层次结构链中,只要它们不被另一个静态成员隐藏,定义为 child class);因此 null 被打印出来,作为引用类型的默认值,是 null;
  2. 同样,您的 B.testValue() returns false,因为 testValue != nullclass A;
  3. 中是错误的
  4. 通过执行 System.out.println(new B());,当您与 class B 交互时,您将在 footrue 之前打印额外的两行(您在问题中省略)第一次定义并将它加载到 JVM 中 - 因此,它的静态块被执行(TEST 被打印并且 testValue (superclass 的)被设置为 "foo");
  5. 然后,你又是System.out.println(B.testValue);,这次这个字段已经用"foo"初始化了,所以打印后者;
  6. 并且 B.valueSet() 将分别打印 true.

也就是:

null
false
TEST
Object Reference, like B@2133c8f8
foo
true