为什么我的泛型不占用子类?

时间:2014-03-20 11:17:00

标签: java generics inheritance

我对类似的泛型yesterday有疑问,作为解决方案,我在某些类中实现了一种自引用,如下所示:

public interface Action { }

public interface Result { }

public interface Player<A extends Action, R extends Result, P extends Player<A, R, P>> {
    default public void onPostAction(final P target, final A action, final R result) { }
}

abstract public class GesturePlayer<A extends Action, R extends Result, P extends GesturePlayer<A, R, P>> implements Player<A, R, P> { }

abstract public class RPSPlayer extends GesturePlayer<RPSGesture, RPSResult, RPSPlayer> { }

public class RPSHumanPlayer extends RPSPlayer {
    @Override
    public void onPostAction(final RPSHumanPlayer target, final RPSGesture gesture, final RPSResult result) { }
}

此代码无法编译,我无法弄清楚原因 如果在@Override我使用RPSPlayer,它确实有效,但RPSHumanPlayer只是它的一个子类,如果它不能与以下相同吗?

List<T> list = new ArrayList<>();

其中类型也定义为超类(List resp RPSPlayer),引用对象的类型作为子类(ArrayLast resp RPSHumanPlayer)。

我对这个问题的目的是收集有关泛型如何正常工作的见解,并且我希望保留RPSHumanPlayer中定义的方法签名。

我认为我对泛型的理解:

  • T是一个类型化参数,如List<String>等。也可以将它用于自己的类和方法。这也捕获了T
  • 的所有子类
  • ?捕获所有可能的Object个。用于确保某些东西是通用的而不是原始的。
  • ? extends T捕获T
  • 的特定子类

此代码是用Java 8编写的。

2 个答案:

答案 0 :(得分:2)

为了在RPSHumanPlayer中实现所需的方法签名,您需要像这样生成RPSPlayer

abstract public class RPSPlayer<P extends RPSPlayer<P>> extends GesturePlayer<RPSGesture, RPSResult, P> { }

然后你可以定义:

public class RPSHumanPlayer extends RPSPlayer<RPSHumanPlayer>

在Java中,参数类型是方法签名的一部分,因此它们不能被更改(甚至不是子类)。从Java 5开始,你可以使用协变返回类型,但就这一点而言。

答案 1 :(得分:1)

你的问题归结为:

public interface Player {
    default public void onPostAction(Player target) {}
}

public abstract class HumanPlayer implements Player {
    @Override
    public void onPostAction(HumanPlayer target) {}
}

这不起作用,因为onPostAction(HumanPlayer)无法覆盖onPostAction(Player),因为如果使用不是Player的{​​{1}}调用会发生什么?