[英]Java referencing final variable before is has been initialized
我有这个超类Creature
及其子类Monster
。 现在我有一个最终变量被引用而没有被初始化的问题。
public class Creature {
private int protection;
public Creature(int protection) {
setProtection(protection);
}
public void setProtection(int p) {
if(!canHaveAsProtection(p))
throw new Exception();
this.protection = p;
}
public boolean canHaveAsProtection(int p) {
return p>0;
}
}
和子类:
public class Monster extends Creature {
private final int maxProtection;
public Monster(int protection) {
super(protection);
this.maxProtection = protection;
}
@Override
public boolean canHaveAsProtection(int p) {
return p>0 && p<maxProtection
}
}
正如你所看到的,当我初始化一个新的Monster
,它会用super(protection)
调用Creature
的构造函数。 在Creature
的构造函数中,方法canHaveAsProtection(p)
被调用,它通过动态绑定获取Monster
被覆盖的一个。 但是,这个覆盖版本使用的最终变量maxProtection
尚未初始化......我该如何解决这个问题?
一些要点:
把这一切放在一起,你的代码应该是这样的:
public class Creature {
private int protection;
protected Creature() {
}
public Creature(int protection) {
setProtection(protection);
}
public void setProtection(int p) {
if (p < 0)
throw new IllegalArgumentException();
this.protection = p;
}
}
public class Monster extends Creature {
private final int maxProtection;
private Monster(int protection) {
this.maxProtection = protection;
setProtection(protection);
}
@Override
public void setProtection(int p) {
if (protection > maxProtection)
throw new IllegalArgumentException();
super.setProtection(p);;
}
public static Monster create(int protection) {
Monster monster = new Monster(protection);
monster.validate();
return monster;
}
}
你还没有显示validate()
方法死了什么,但是如果只需要保护检查,我会删除它和静态工厂方法并使Monster的构造函数公开。
Monster
不会在您发布的代码中扩展Creature
。
如果确实如此,我认为Monster
没有理由拥有最终变量。 Creature
应该有最终变量,而Monster
应该只是访问它。 如果需要对保护进行最大值验证,那么在我看来,所有的Creature
实例都应该拥有它。
把它从Monster
推到Creature
,你很好。 你应该在Creature
构造函数中有两个参数: protection
和maxProtection
。 如果maxProtection < 0
或protection
超出0..maxProtection
范围,则抛出IllegalArgumentException
。
这与你的初始化链有关。
在初始化父级之前,必须完全初始化子类。
目前,它看起来像这样......
怪物 - >生物 - >生物#setProtection->怪物#canHaveAsProtection ......
其中maxProtextion尚未初始化,因为Creature constrcutor尚未返回。
一个解决方案是推迟初始化一些方法,也许是在构造函数可以调用的init方法中
在构造函数中调用公共方法确实是一种不好的做法,尤其是当您希望将其子类化时。
你的类应该是可靠的并且独立地初始化它的状态。 我认为你应该在构造函数中显式设置protection
变量:
public Creature(int protection) {
this.protection = protection;
}
如果您确实想在构造函数中验证参数,那么将常用功能提取到私有方法:
public Creature(int protection) {
Assert.isTrue(isProtectionValid(p));
this.protection = protection;
}
private static boolean isProtectionValid(int p) {
return p > 0;
}
public boolean canHaveAsProtection(int p) {
return isProtectionValid(p);
}
基于其他答案中提到的原因,请执行以下操作:
public Creature(int protection) {
this.protection = protection;
}
public Monster(int protection) {
super(protection + 1);
this.maxProtection = protection;
}
由于< maxProtection
校正+ 1
似乎是您的预期逻辑。
如何覆盖设置保护设置max first en而不是超级设置保护。
@override
public void setProtection(int p) {
this.maxProtection = p;
super.setProtection(p);
}
您不应该在构造函数中调用公共方法。 相反,您可以将构造函数修饰符更改为protected / private,并使用调用验证的工厂方法:
public class Creature {
private int protection;
protected Creature(int protection) {
this.protection = protection;
}
public void setProtection(int protection) {
if (!canHaveAsProtection(protection))
throw new IllegalArgumentException();
this.protection = protection;
}
public boolean canHaveAsProtection(int protection) {
return protection > 0;
}
protected void validate() {
if (!canHaveAsProtection(this.protection))
throw new IllegalArgumentException();
}
public static Creature create(int protection) {
Creature creature = new Creature(protection);
creature.validate();
return creature;
}
}
和Monster
:
public class Monster extends Creature {
private final int maxProtection;
private Monster(int protection) {
super(protection);
this.maxProtection = protection;
}
@Override
public boolean canHaveAsProtection(int p) {
// I changed '<' to '<=' because '<' wouldn't work anyway
return p > 0 && p <= maxProtection;
}
public static Monster create(int protection) {
Monster monster = new Monster(protection);
monster.validate();
return monster;
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.