在Java中如何在子类中初始化静态常量变量?

5

我有一个如下的类:

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

我想在子类中初始化变量FIELD,就像这样:

public class B extends A {
    FIELD = 5;
}

编辑 实际上,我有多个类继承了A类,并且它们都有一个名为FIELD的变量,但其值不同;所以我找到的方法是重构变量FIELD并在超类中声明它。还有其他解决方案吗? 是否可能有这样的东西? 谢谢您的帮助。


1
请看这里 - User42
1
每个子类都不会有自己的静态字段副本。它由整个 JVM 中运行的所有内容共享(假设没有花哨的类加载器)。静态字段/方法不是多态的一部分。 - lance-java
谢谢 @LanceJava。那是我没有注意到的重要点。所以对于这个问题,我应该为A的所有子类声明变量FIELD吗? - Danial Alihosseini
这取决于您计划如何使用FIELD。如果它仅在每个子类中使用,那么是的,在每个子类中定义它。如果您希望将其放在某个抽象基类中,则可以在构造函数中传递它。我倾向于避免继承,并最终创建一个带有getter()的接口来获取该字段。 - lance-java
如果你正在将它变成静态的,那么很有可能你做错了!!!你应该采用依赖注入和可测试性的方式!!! - lance-java
显示剩余3条评论
8个回答

5
重点是超类的子类没有超类中声明的静态字段的副本,而是在它们之间共享该字段;因此,在不同的子类中无法使用具有不同值的静态变量。因此,我将在所有子类中声明变量FIELD。
我从评论中的@LenceJava获取了所有这些信息。 感谢@LanceJava。

1
当您创建一个新的B对象时,首先会自动创建一个新的A对象,并在其默认构造函数中初始化其最终变量;因此,您将无法再修改它们的值。

1
这是不可能的(至少没有一些严重的诡计是不可能的)
当初始化A时,该字段必须被初始化。 A在B之前初始化。在B中的任何内容只有在或之后才会执行B初始化。
如果这是可能的,在加载B之前使用A.FIELD时应该发生什么?
您可以将字段设置为私有且非静态,并提供一个setter,只允许调用一次并从B中调用它。
在大多数像这样的情况下,实际问题有更清晰的解决方案,但由于您没有提到要解决的实际问题,因此我们无法在这方面提供帮助。

1

由于它是staticfinal,所以在初始化或静态块中您可以为该变量分配值。但只限于此处。


0

无论是否使用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 (#5:13)
|        at (#7:1)

现在已初始化:

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

0

如果您想在派生类中更改静态常量变量,则不能在最终类中拥有它们。

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

0

final变量在声明时就被初始化,并且它们不能被后续的子类重新初始化或修改。在 Java 中,final表示常量。试图修改它们的值会导致编译错误。


-2

这应该可以工作。

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

通过这个实现,当创建B的实例时,FIELD将只有它的值,并且静态约束将不起作用。我的意思是,在没有任何B的实例时,FIELD的值将不可用。我说得对吗? - Danial Alihosseini
现在该字段不再是静态的了,这意味着FIELD的值与A的实例数量一样多.... - Jens Schauder
无法初始化既是 final 又是 static 的变量。 - Gaur93
要初始化一个final变量,我们使用通过其类构造函数进行初始化的概念。 - Gaur93

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接