Java 用静态块重写静态字段是一种错误的做法吗?
我想创建数据结构以捕获以下想法: 在游戏中,我希望有一个通用的Java 用静态块重写静态字段是一种错误的做法吗?,java,static,subclassing,Java,Static,Subclassing,我想创建数据结构以捕获以下想法: 在游戏中,我希望有一个通用的技能类,它可以捕获技能id、冷却时间、法力消耗等一般信息 然后,我想拥有定义实际互动和行为的特定技能。所以这些都是从基类技能扩展而来的 最后,每个玩家都有这些特定技能的实例,所以我可以检查每个玩家的技能状态,最近是否有玩家使用过,等等 因此,我有一个抽象的超类Skill,它定义了一些静态变量,所有技能都有相同的静态变量,然后对于扩展Skill的每个技能,我使用一个静态块来重新分配静态变量。因此,我有以下模式: class A {
技能类,它可以捕获技能id、冷却时间、法力消耗等一般信息
然后,我想拥有定义实际互动和行为的特定技能。所以这些都是从基类技能扩展而来的
最后,每个玩家都有这些特定技能的实例,所以我可以检查每个玩家的技能状态,最近是否有玩家使用过,等等
因此,我有一个抽象的超类Skill
,它定义了一些静态变量,所有技能都有相同的静态变量,然后对于扩展Skill
的每个技能,我使用一个静态块来重新分配静态变量。因此,我有以下模式:
class A {
static int x = 0;
}
class B extends A {
static {
x = 1;
}
}
...
// in a method
A b = new B();
System.out.println(b.x);
上面打印的是1,这正是我想要的行为。我唯一的问题是系统抱怨我以非静态方式访问静态变量。但是我当然不能用那种方式访问它,因为我只想把这个技能当作skill
,而不知道它到底是哪个子类。因此,每次我这样做时都必须抑制警告,这让我思考是否有更好/更整洁的设计模式
我曾考虑过将所讨论的变量设置为非静态变量,但因为它们在特定技能的所有实例中都应该是静态的,所以我觉得它应该是一个静态变量…您通常应该避免使用全局状态。如果您确定字段x
将在基类的所有子类型的所有实例中共享,那么放置此类字段的正确位置可能不是基类。它可能位于其他一些配置对象中
但即使使用当前的配置,它也没有意义,因为任何修改静态变量的子类都会使变量对所有类可见。如果子类B
将x
更改为1,则子类C
将其更改为2,新值也将对B
可见
我认为,按照你在问题中描述的方式,每个子类都应该有自己独立的静态字段。在抽象基类中,您可以定义每个子类要实现的方法,以便访问每个字段:
abstract class A {
public abstract int getX();
}
class B extends A {
public static int x = 1;
public int getX() {
return x;
}
}
class C extends A {
public static int x = 2;
public int getX() {
return x;
}
}
正如一些回答和评论所指出的,您的方法不会按您想要的方式工作,因为每个静态块都会更改扩展A
的所有类的静态变量
改用接口和实例方法:
public interface A {
int getX();
}
-
-
如果每个技能子类都有自己的值x,那么在每个子类中都应该有一个静态x
字段。按原样,加载B类会将A.x设置为1。让你的x变量成为最终变量。如果希望以多态方式访问变量值,那么每个类中都应该有一个非静态的getX()
方法。它是否总是返回相同的常量值是一个实现细节。。。您不会更改特定技能的所有实例,而是更改所有技能的所有实例,因为您更改了类A
中的属性(我假定它是您的AbstractSkill
类)。因此,对于扩展A
的所有类,x
都是1
。我倾向于为您的技能使用一个接口,定义所需的方法并隐藏实现细节。您可以使用某种public int getX()
,而不关心实现。这只是一个完整的旁白,但我会将这两件事完全分开:我会有一个SkillInfo
class/enum,它包含关于技能的所有通用信息(名称、描述、先决条件等),技能不会扩展它,每个都有一个实例。您可以创建单独的类来实现技能行为,每个技能对应一个类。代码似乎根本不起作用!好吧,既然Java不允许重写静态方法,我想没有办法使这些共享变量成为静态的……嗯,看来我应该对它进行更广泛的测试。但是,您将如何对其进行建模?我想我的问题是我想声明一个抽象方法/字段,我觉得它也应该是静态的,因为在子类中,值在所有实例中都是常量。没有抽象字段这样的东西,抽象方法也不能是静态的。我认为,按照你在问题中描述的方式,每个子类都应该有自己独立的静态字段,但这样我就失去了抽象。例如,我不能遍历Skill
的列表,我知道其中每个都有一个名为foo
的静态变量,而不知道每个实例是什么子类。我也不希望使用反射。正如在其他注释中提到的,您可以在基类中定义一个抽象方法,每个子类都可以实现该方法来返回该静态字段。请参阅我更新的答案。但是,由于该值在B的所有实例中都是常量,我觉得把它作为一个a知道的静态方法更优雅…我猜Java中确实不支持这个方法…在B的所有实例中只有一个X的静态实例。但是正如您正确猜测的那样,没有办法使用a中定义的静态字段或方法来做您想做的事情。
public class B implements A {
private static final int X = 1;
@Override
public int getX() {
return X;
}
}
A myInstance = new B();
System.out.println(myInstance.getX()); // prints "1"