Универсальный класс <T extends A> использует статическое поле вместо поля T - PullRequest
1 голос
/ 20 января 2012

Вот моя ситуация

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();
    }
}

Я всегда получаю nullPointerException, когда конструктор A вызывает doSomething, потому что action имеет значение null ..

Поскольку B расширяет A, я ожидал, что он будет использовать SimpleActions.STAND, а не Actions.STAND.

Что я делаю не так? Как мне это сделать?

Ответы [ 2 ]

3 голосов
/ 20 января 2012

Параметры типа для универсального не известны во время выполнения. Другими словами, во время выполнения нет никакой разницы между 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 голос
/ 20 января 2012

Спецификация языка Java пишет :

Члены переменной типа X со связанными T & I1 ... In являются членами типа пересечения (§4.9) T & I1 ... При появлении в точке, где объявлена ​​переменная типа.

Вот почему выражение T.STAND относится к Actions.STAND, а не SimpleActions.STAND.

Actions.STAND и SimpleActions.STAND - это разные поля (в отличие от нестатических методов, поля не могут быть переопределены.)

Это уже выдвигает на первый план один из способов делегирования подклассу: Определите метод доступа (метод получения), который подкласс должен переопределить:

abstract class Actions {
    abstract Actions stand();
}

class SimpleActions extends Actions {
    private static final Actions STAND = ...;

    @Override Actions stand() { return STAND;}
}

и вызвать

t.stand();

где t - это экземпляр T, предоставленный A при создании. Или, возможно, переместите этот метод в другой тип (MotionRegistry?) И предоставьте экземпляр этого при построении A.

Тем не менее, ваш дизайн кажется довольно сложным, я не могу избавиться от ощущения, что ваш код может быть упрощен (вам нужно различие между Actions и SimpleActions, если оба описывают одни и те же действия?)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...