Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/394.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 用静态块重写静态字段是一种错误的做法吗?_Java_Static_Subclassing - Fatal编程技术网

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"