首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么不能将从另一个泛型类扩展的类作为泛型类传递?

为什么不能将从另一个泛型类扩展的类作为泛型类传递?
EN

Stack Overflow用户
提问于 2020-08-25 16:59:18
回答 1查看 101关注 0票数 0

我开发了一些大型项目。我代码的某些部分:

1)

代码语言:javascript
复制
private final ObjectPool<ProcessorMechanicsRoom> processorsPool;
... new ProcessorMechanicsRoom(processorsPool);

代码语言:javascript
复制
public class ProcessorMechanicsRoom
        extends ProcessorMechanics<ProcessMechanicsRoom, IMechanicsRoom, IMechanicsRoomCallback> {
    ...
    public ProcessorMechanicsRoom(ObjectPool<ProcessorMechanicsRoom> pool) {
}
    super(pool); // the problem is here
}

代码语言:javascript
复制
public class ProcessorMechanics
        <P extends ProcessMechanics<M,C>, M extends IAMechanics<C>, C extends IAMechanicsCallback>
        extends Processor<P> {
    private final ObjectPool<ProcessorMechanics<P,M,C>> pool;
    ...
    public ProcessorMechanics(ObjectPool<ProcessorMechanics<P,M,C>> pool) {...}
    ...

}

问题是ObjectPool不能传递给超级构造函数(代码2)。所以我很困惑。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-08-25 17:25:39

有一种叫做方差的东西。

让我们使用一些我们都熟悉的类型:

java.lang.Integer extends java.lang.Number extends java.lang.Object

协方差

在协变量系统中,您可以编写:

Number x = new Integer();

但你不能写:

Integer y = new Number();

正如您可能猜测的那样,java中的基本赋值和其他任务都是协变的。但这不是唯一的办法。

反方差

在反变体系统中,不能编写

Number x = new Integer();

但另一方面,这实际上是可行的:

Integer y = new Number();

不变性

这是一个僵化的问题,在这个问题上,两者都不起作用。你唯一能做的就是:

Integer y = new Integer();

好吧,那么,仿制药呢?

java对于基本内容来说是协变的,而泛型不是协变的,泛型是反变的,或者是协变的,或者是不变的,这取决于您如何编写泛型。

List<? extends Number> list = new ArrayList<Integer>(); // legal

  • Contravariant:List<? super Integer> list = new ArrayList<Number>(); // legal

  • Invariant:List<Integer> list = new ArrayList<Integer>(); // only integer will do here

  • 协变量

你选择了不变的。所以只有ProcessorMechanics才能做到;您的ProcessorMechanicsRoom是一个子类,因此您不能这样做,除非您的类型关系允许协方差,而它不允许。把? extends做好,它就能工作了。

呃,wtf?为什么?

因为..。生活。现实生活就是这样运作的。

想象一下没有。我可以做到这一点,然后打破一切:

代码语言:javascript
复制
List<Integer> ints = new ArrayList<Integer>();
List<Number> numbers = ints; // MARK THIS LINE!
numbers.add(new Double(5.0));
Integer x = ints.get(0); // ERROR!

在上面,如果它已经编译并运行,最后一行将是一个错误,因为.get(0)调用将检索一个不是整数的双值。幸运的是,上面没有编译;错误发生在标记行上。那是..。因为编译器应该不允许这样做。泛型的本质是是不变的

现在,协方差可以存在。例如,如果您有一个方法来总结对每个数字调用.intValue()的结果,那么您可以编写:

代码语言:javascript
复制
public int sumAll(List<Number> list) {
   int result = 0;
   for (Number n : list) result += n.intValue();
   return result;
}

但是这是编写它的不好的方法;您已经命令参数是不变的,因此,您不能将List<Integer>传递给这个东西。但代码是协变的。如果您传递一个整数列表,它也会工作得很好。因此,您应该将其写为public int sumAll(List<? extends Number> numbers)

这里有一个不变性的例子:

代码语言:javascript
复制
public void addSumToEnd(List<Number> list) {
    int sum = 0;
    for (Number n : list) sum += n.intValue();
    list.add(sum);
}

因为我们在这里加了一个数字,你不能写List<? extends Number>。毕竟,我们正在添加一个int,您不能在List<Double>上这样做。您可以在这里提供的唯一可接受的列表是List<Number>List<Integer>,并且无法用java来表示。

对于列表来说,这很简单:“inver方差= adds”(.add().addAll()等)、“协方差=读”、“不变性=两者兼而有之”。对于其他泛化的类型,它可能没有那么简单。

假设您的ProcessorMechanics类只会“读取”,那么您可以使它是协变的,并编写:

代码语言:javascript
复制
public ProcessorMechanics(ObjectPool<? extends ProcessorMechanics<P, M, C>> pool) {...}
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/63583738

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档