【问题标题】:Generic <T extends A> class uses A static field instead of T's oneGeneric <T extends A> 类使用一个静态字段而不是 T 的一个
【发布时间】:2012-01-20 02:19:52
【问题描述】:

这是我的情况

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。

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

【问题讨论】:

  • 您从类 B 调用 super() - 在超类级别,编译器所知道的只是 T 扩展 Actions,而不是 SimpleActions。您是否考虑过使用Enum 来执行您的操作,或者是否需要“覆盖”它们?如果有,Java 不会像您对 Smalltalk 所期望的那样进行静态继承;正如您的代码一样,Actions 类中的静态声明有点毫无意义。

标签: java class inheritance


【解决方案1】:

泛型的类型参数在运行时是未知的。换句话说,在运行时,A&lt;Actions&gt;A&lt;SimpleActions&gt; 之间没有区别。因此,jvm 无法判断您想要SimpleActions.STAND,而不是Actions.STAND。如果您需要在运行时知道类型参数,则需要将它们放在一个单独的变量中。

如果不清楚,请阅读“运行时类型擦除”。

根据您的评论进行了编辑 - 如果您只在构造函数中执行此逻辑,则可以使构造函数看起来像

A( Class<? extends Action> actionType ){
    if( SimpleActions.class.isAssignableFrom( actionType )){
        doSomething( SimpleActions.STAND );
    }
    else{
        doSomething( Actions.STAND );
    }
}

如果在构造函数之外需要相同的逻辑,则在A 内创建一个Class&lt;? extends Action&gt; 类型的成员变量来存储actionType

【讨论】:

  • 是的,我读过它。但是我怎么能把它放在一个单独的变量中呢?你能给我看一些(伪)代码吗?
  • 这个接缝了很多工作,另外我会使用许多动作之王的实现,所以它会变成 if else 的墙
【解决方案2】:

Java 语言规范writes

具有绑定 T & I1 ... In 的类型变量 X 的成员是交集类型 (§4.9) T & I1 ... In 的成员,出现在声明类型变量的位置。

这就是为什么表达式 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 吗?)

【讨论】:

  • 谢谢!即使我将方法设为静态,它是否有效?是的,我有,因为我有许多扩展 A 的不同类,每个类都有自己的动作,逻辑上总是相同的,但图形上是不同的。
  • @Makers_F:不,它不适用于静态方法。静态方法的重点是将方法与特定的类实现联系起来。这种方法利用了仅适用于非静态方法的多态性。
  • @StriplingWarrior 起初我认为泛型会帮助我,但我使用它们的次数越多,我发现它们越弱。顺便说一句,谢谢你的提示!回到为一个如此简单的东西编写大量无聊的代码..
  • 在这里使用公共静态非最终变量是一个真正的错误,因为它们可以重新分配。从泛型类型引用它们是令人困惑的。从几个方面来看,这是一个糟糕的设计。如果您正确使用泛型,它们可能会非常适合您。
  • @StriplingWarrior 是的,我现在将其更改为单例(因此我可以在任何需要的地方访问它,而无需始终在我的类中为此引入一个字段),它实现了像 Meriton 所说的接口。我不了解java的泛型可能是真的,但我也希望这种经验能教会我!感谢您的努力!
猜你喜欢
  • 2022-01-21
  • 2014-06-08
  • 2021-03-26
  • 2020-11-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-24
相关资源
最近更新 更多