这是我的情况
public abstract class Actions {
public static Actions STAND;
public static Actions ATTACK;
public static Actions COLONIZE;
public static Actions DEFEND;
public static Actions TURN_CW;
public static Actions TURN_CCW;
public static Actions DIE;
public abstract long[] getFramesDurations();
public abstract int[] getBaseTiles();
}
public class SimpleActions extends Actions{
public static Actions STAND = new SimpleActions( new long[]{120,120,120,120,120,120,120}, new int[]{0,1,2,3,4,5,6});
public static Actions ATTACK = new SimpleActions( new long[]{120,120,120,120,120,120,120,120,120}, new int[]{7,8,9,10,11,12,13,14,15});
public static Actions COLONIZE = new SimpleActions( new long[]{120,120,120,120,120,120,120}, new int[]{7,8,9,10,11,12,13,14,15});
public static Actions DEFEND = new SimpleActions(new long[]{1}, new int[]{1});
public static Actions TURN_CW = new SimpleActions( new long[]{1}, new int[]{1});
public static Actions TURN_CCW = new SimpleActions( new long[]{1}, new int[]{1});
public static Actions DIE = new SimpleActions( new long[]{1}, new int[]{1});
private final long[] mActionFramesDurations;
private final int[] mActionBaseTiles;
SimpleActions(long[] pActionFramesDurations, int[] pActionBaseTiles) {
mActionFramesDurations = pActionFramesDurations;
mActionBaseTiles = pActionBaseTiles;
}
public long[] getFramesDurations()
{
return mActionFramesDurations;
}
public int[] getBaseTiles()
{
return mActionBaseTiles;
}
}
public abstract class A<T extends Actions> {
A() {
doSomething(T.STAND);
}
protected void doSomething(Actions action) { use action somewhere}
}
public class B extends A<SimpleActions> {
B() {
super();
}
}
当A的构造函数调用doSomething时,我总是得到nullPointerException,因为action为null ..
由于B扩展A我期望它使用SimpleActions.STAND,而不是Actions.STAND。
我做错了什么?我该怎么做?
答案 0 :(得分:3)
通用的类型参数在运行时是未知的。换句话说,在运行时,A<Actions>
和A<SimpleActions>
之间没有区别。因此,jvm无法告诉您需要SimpleActions.STAND
,而不是Actions.STAND
。如果您需要在运行时知道类型参数,则需要在单独的变量中携带它们。
如果不清楚,请阅读“运行时类型擦除”。
在您的评论后编辑 如果您只在构造函数中执行此逻辑,则可以使构造函数看起来像
A( Class<? extends Action> actionType ){
if( SimpleActions.class.isAssignableFrom( actionType )){
doSomething( SimpleActions.STAND );
}
else{
doSomething( Actions.STAND );
}
}
如果你需要在构造函数之外使用相同的逻辑,那么在Class<? extends Action>
中创建一个A
类型的成员变量来存储actionType
。
答案 1 :(得分:1)
Java语言规范writes:
带有绑定T&amp;的类型变量X的成员I1 ... In是交叉类型的成员(§4.9)T&amp; I1 ......出现在声明类型变量的位置。
这就是为什么表达式T.STAND
引用Actions.STAND
,而不是SimpleActions.STAND
。
Actions.STAND
和SimpleActions.STAND
是不同的字段(与非静态方法不同,字段无法覆盖。)
这已经强调了委托子类的一种方法:定义子类必须覆盖的访问器方法(getter):
abstract class Actions {
abstract Actions stand();
}
class SimpleActions extends Actions {
private static final Actions STAND = ...;
@Override Actions stand() { return STAND;}
}
并调用
t.stand();
其中t是在构造时提供给A
的T的实例。或者将此方法移动到其他类型(MotionRegistry
?)并在构造A
时提供该实例。
那就是说,你的设计显得相当复杂,我不能动摇你的代码可以被简化的感觉(如果两者都描述相同的动作,你是否需要区分Actions和SimpleActions?)