在 java 中初始化子 class(sub class) 中的静态最终变量

initialize static final variable in child class(sub class) in java

我有一个 class 这样的:

public abstract class A {
    public static final int FIELD;
    // some methods
}

我想在子 class 中初始化变量 FIELD。 我的意思是这样的:

public class B extends A {
    FIELD = 5;
}

编辑 实际上我有多个扩展 A 的 classes 并且它们都具有变量 FIELD 但具有不同的值;所以我找到的方法是重构变量 FIELD 并在 super class 中声明它。还有其他解决方案吗? 有可能有这样的东西吗? 谢谢你的帮助。

不,这是不可能的(至少不是没有一些严重的肮脏技巧)

字段必须在 A 初始化时初始化。 AB 初始化之前被初始化。 B 中的任何内容仅在 B 初始化时或之后执行。

如果这是可能的,在加载 B 之前使用 A.FIELD 时会发生什么?

你可以做的是将字段设为私有而不是静态的,并提供一个 setter 只允许对其进行一次调用并从 B 调用它。

在像这样的大多数情况下,对于实际问题有更简洁的解决方案,但由于您没有提及您尝试解决的实际问题,我们在这方面无能为力。

final 变量在声明时被初始化,以后不能在子 class 中重新初始化或修改。 java中的final表示常量。尝试修改它们的值会导致编译错误。

因为它是 staticfinal,在初始化时和/或在静态块中,您可以为该变量赋值。只是没有其他地方。

这应该可以。

public class A {
public final int FIELD;
A(int a){
this.FIELD=a;
}
}
public class B extends A {
B(int a){
super(a);
}
}

如果您想在派生的 classes 中更改静态最终变量,则不能在 final class 中使用它们。

1) 删除 FIELD 属性的 final 关键字

2) 修改代码如下

import java.io.*;
import java.util.*;

class A {
    public static int FIELD = 4;
}
class B extends A {
    public B(){
        this.FIELD  = 5;
    }
}
public class Test {

    public static void main(String args[]) throws Exception {
    B b = new B();
        System.out.println("B value:"+b.FIELD);
    }

}

输出为:

B value:5

关键是 super class 的子 classes 没有在 super class 和 super class 中声明的静态字段的副本在他们之间分享;所以没有办法在不同的子 classes 中有一个具有不同值的静态变量。因此,我将在所有子 classes.
中声明变量 FIELD 我在评论中从@LenceJava 获得了所有这些。 谢谢@LanceJava。

当您创建一个新的B对象时,首先会自动创建一个新的A对象,并在其默认构造函数中初始化其final变量;所以你不能再修改它们的值了。

无论 final 关键字如何,单个静态变量都不适用于多个子 class,因为每当实例化新子 class 时,单个静态变量就会被重新分配。此外,实例化的顺序仍然会进一步混淆最后静态更新的值。

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
 ==> "A"    

jshell> A.STATIC_SUPER_VAR
 ==> "A"

jshell> new B()
 ==> B@685cb137

jshell> B.STATIC_SUPER_VAR
 ==> "B"

jshell> A.STATIC_SUPER_VAR
 ==> "B"

jshell> public class C extends A { public C() { STATIC_SUPER_VAR = "C";} }
|  created class C

jshell> new C()
 ==> C@5f2108b5

jshell> A.STATIC_SUPER_VAR
 ==> "C"

jshell> B.STATIC_SUPER_VAR
 ==> "C"

jshell> C.STATIC_SUPER_VAR
 ==> "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

确保子 class 已初始化,我的意思是在访问之前更新静态地图, 否则 NPE

jshell> B.getClassSpecificInteger(B.class)
|  Exception java.lang.NullPointerException
|        at A.getClassSpecificInteger (#5:13)
|        at (#7:1)

现在初始化:

jshell> new B(10);
 ==> B@610694f1

jshell> new C(20)
 ==> C@50b494a6

现在静态访问它,子目录中没有 FIELDclass:

jshell> B.getClassSpecificInteger(B.class)
 ==> 10

jshell> A.getClassSpecificInteger(B.class)
 ==> 10

jshell> B.getClassSpecificInteger(C.class)
 ==> 20