我有这个超类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
时,它会使用Creature
调用super(protection)
的构造函数。在Creature
的构造函数中,调用方法canHaveAsProtection(p)
,通过动态绑定获取Monster
中的覆盖方法。但是,此覆盖版本使用尚未初始化的最终变量maxProtection
...
我怎么解决这个问题?
答案 0 :(得分:1)
有些观点:
总而言之,您的代码应如下所示:
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的构造函数设为公开。
答案 1 :(得分:0)
Monster
不会在您发布的代码中展开Creature
。
如果是,我认为Monster
没有理由拥有最终变量。 Creature
应该有最终变量,而Monster
应该只是访问它。如果需要对保护进行最大值验证,那么在我看来,所有Creature
个实例都应该拥有它。
将它从Monster
推到Creature
,你没事。您应该在Creature
构造函数中有两个参数:protection
和maxProtection
。如果IllegalArgumentException
或maxProtection < 0
超出范围protection
,则会引发0..maxProtection
。
答案 2 :(得分:0)
这与你的初始化链有关。
在初始化父级之前,必须完全初始化子级。
目前,它看起来像......
Monster-&GT; Creature-&GT;生物#setProtection-&GT;怪物#canHaveAsProtection ...
其中maxProtextion尚未初始化,因为Creature constrcutor尚未返回。
一个解决方案是推迟初始化一些方法,也许在构造函数可以调用的init方法中
答案 3 :(得分:0)
在构造函数中调用公共方法确实是一种不好的做法,特别是当你希望将它子类化时。
你的班级应该是坚实的,并独立地初始化它的状态。
我认为你应该在构造函数中明确设置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);
}
答案 4 :(得分:0)
由于其他答案中提到的原因,请执行:
public Creature(int protection) {
this.protection = protection;
}
public Monster(int protection) {
super(protection + 1);
this.maxProtection = protection;
}
由于+ 1
。
< maxProtection
似乎是您的预期逻辑
答案 5 :(得分:0)
如何覆盖设置保护设置max first en而不是超级设置保护。
@override
public void setProtection(int p) {
this.maxProtection = p;
super.setProtection(p);
}
答案 6 :(得分:0)
您不应该在构造函数中调用公共方法。相反,您可以将构造函数修饰符更改为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;
}
}