java中的最终字段继承

时间:2011-10-21 05:26:35

标签: java inheritance field final

是否可以让给定的子类在其超类中初始化静态最终字段?基本上我希望子类配置所需的类范围变量。不幸的是,abstract关键字并不完全适用于字段..

2 个答案:

答案 0 :(得分:5)

不 - 如果有两个子类试图做同样的事情,你会怎么看?如果你有静态的最终字段,它们必须由声明它们的类初始化。

如果您正在尝试一起使用静态字段和继承,那么通常表示开始时出现问题,说实话 - 这两个概念通常不能很好地发挥作用一起。人们经常试图用静态方法等来“伪造”继承,而且通常结尾很糟糕 - 这听起来像是对这个主题的变异。

如果您能描述更广泛的图景,我们可以为您提供更多帮助。顺便说一下,为了可测试性,我会强烈建议您避免使用静态 。它们适用于真正的常量,但如果它与配置类似,那么在构造对象(IMO)时传递相关设置会更好。

编辑:我可以看到四种可以更好地模拟你的情况的选项:

  1. 使用注释:参见True Soft的回答
  2. maxHealth成为方法,这样你就可以向任何玩家询问他们的最大健康状况 - 那就是多态,所以可以在每个类中被覆盖
  3. 分别为PlayerPlayerClass模型:

    public class Player {
        private final PlayerClass playerClass;
        private int health; // etc
    }
    
    public class PlayerClass {
        private final int maxHealth; //etc
    }
    

    这样可以在“玩家类”级别继承,但你不必 - 你可以创建几个行为的PlayerClass个实例以相同的方式,但具有不同的统计数据......或者您可以将PlayerClass子类化为自定义行为。此时,您可能根本不需要Player的不同子类。

  4. 与想法3相同,但使用枚举:

    public enum PlayerClass {
        ELF(10), DWARF(9), HUMAN(5);
    
        private final int maxHealth;
        private PlayerClass(int maxHealth) {
            this.maxHealth = maxHealth;
        }
    }
    
  5. 我个人认为我的偏好是最终选择,我怀疑。你可以仍然覆盖行为,但你有一组固定的可能类 - 这可能会合理地准确地模拟你的游戏。

答案 1 :(得分:1)

关于Jon Skeet的回答,我认为这不是那么糟糕“如果你试图一起使用静态字段和继承”。我建议你使用注释:

@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@interface AValue {
    /**
     * @return something final that is "static" (attached to a class), 
     * but also "abstract" (looks that it be changed in the subclasses)
     */
    String value();
}

@AValue("A default value") // you can ommit this, but all subclasses should add the annotation (so the method from Utils work OK)
abstract class A { }

@AValue("Value for class B")
class B extends A { }

@AValue("Value for class C")
class C extends A { }

class Utils {
    static String getValueOfClass(Class<? extends A> clazz) {
        return clazz.getAnnotation(AValue.class).value();
    }
}