无论是否使用final关键字,单个静态变量对于多个子类都不起作用,因为每当实例化新的子类时,单个静态变量就会被重新赋值。此外,实例化的顺序仍然会进一步混淆最后静态更新的值是什么。
jshell> public abstract class A { public static String STATIC_SUPER_VAR = "A"; }
| created class A
jshell> public class B extends A { public B() { STATIC_SUPER_VAR = "B"; } }
| created class B
jshell> B.STATIC_SUPER_VAR
$3 ==> "A"
jshell> A.STATIC_SUPER_VAR
$4 ==> "A"
jshell> new B()
$3 ==> B@685cb137
jshell> B.STATIC_SUPER_VAR
$4 ==> "B"
jshell> A.STATIC_SUPER_VAR
$5 ==> "B"
jshell> public class C extends A { public C() { STATIC_SUPER_VAR = "C";} }
| created class C
jshell> new C()
$7 ==> C@5f2108b5
jshell> A.STATIC_SUPER_VAR
$8 ==> "C"
jshell> B.STATIC_SUPER_VAR
$9 ==> "C"
jshell> C.STATIC_SUPER_VAR
$10 ==> "C"
解决方案
我们可以使用静态 Map 而不是单个静态变量。
jshell> public abstract class A {
...>
...> private static Map<Class<? extends A>, Integer> CLASS_FIELD_HOLDER = new HashMap<>();
...>
...> public A (int classSpecificInteger) {
...>
...> CLASS_FIELD_HOLDER.put(getClass(), classSpecificInteger);
...> }
...>
...>
...> public static int getClassSpecificInteger(Class<? extends A> clazz) {
...>
...> return CLASS_FIELD_HOLDER.get(clazz);
...> }
...> }
| created class A
jshell> public class B extends A {
...>
...> public B (int classSpecificInteger) {
...>
...> super(classSpecificInteger);
...> }
...> }
| created class B
jshell> public class C extends A {
...>
...> public C (int classSpecificInteger) {
...>
...> super(classSpecificInteger);
...> }
...> }
| created class C
确保子类被初始化,我是指在访问之前静态映射已更新,否则会引发 NPE。
jshell> B.getClassSpecificInteger(B.class)
| Exception java.lang.NullPointerException
| at A.getClassSpecificInteger (
| at (
现在已初始化:
jshell> new B(10)
$8 ==> B@610694f1
jshell> new C(20)
$9 ==> C@50b494a6
现在以静态方式访问它,而无需在子类中拥有FIELD:
jshell> B.getClassSpecificInteger(B.class)
$10 ==> 10
jshell> A.getClassSpecificInteger(B.class)
$11 ==> 10
jshell> B.getClassSpecificInteger(C.class)
$12 ==> 20