Generic <t extends =“”a =“”>类使用静态字段而不是T的一个</t>

时间:2012-01-20 02:19:52

标签: java class inheritance

这是我的情况

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。

我做错了什么?我该怎么做?

2 个答案:

答案 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.STANDSimpleActions.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?)