在 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
初始化时初始化。 A
在 B
初始化之前被初始化。 B
中的任何内容仅在 B
初始化时或之后执行。
如果这是可能的,在加载 B 之前使用 A.FIELD
时会发生什么?
你可以做的是将字段设为私有而不是静态的,并提供一个 setter 只允许对其进行一次调用并从 B
调用它。
在像这样的大多数情况下,对于实际问题有更简洁的解决方案,但由于您没有提及您尝试解决的实际问题,我们在这方面无能为力。
final
变量在声明时被初始化,以后不能在子 class 中重新初始化或修改。 java中的final
表示常量。尝试修改它们的值会导致编译错误。
因为它是 static
和 final
,在初始化时和/或在静态块中,您可以为该变量赋值。只是没有其他地方。
这应该可以。
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
我有一个 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
初始化时初始化。 A
在 B
初始化之前被初始化。 B
中的任何内容仅在 B
初始化时或之后执行。
如果这是可能的,在加载 B 之前使用 A.FIELD
时会发生什么?
你可以做的是将字段设为私有而不是静态的,并提供一个 setter 只允许对其进行一次调用并从 B
调用它。
在像这样的大多数情况下,对于实际问题有更简洁的解决方案,但由于您没有提及您尝试解决的实际问题,我们在这方面无能为力。
final
变量在声明时被初始化,以后不能在子 class 中重新初始化或修改。 java中的final
表示常量。尝试修改它们的值会导致编译错误。
因为它是 static
和 final
,在初始化时和/或在静态块中,您可以为该变量赋值。只是没有其他地方。
这应该可以。
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