问题描述
1)
private final ObjectPool<ProcessorMechanicsRoom> processorsPool;
... new ProcessorMechanicsRoom(processorsPool);
public class ProcessorMechanicsRoom
extends ProcessorMechanics<ProcessMechanicsRoom,IMechanicsRoom,IMechanicsRoomCallback> {
...
public ProcessorMechanicsRoom(ObjectPool<ProcessorMechanicsRoom> pool) {
}
super(pool); // the problem is here
}
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,C>> pool) {...}
...
}
问题是无法将ObjectPool
解决方法
有一个叫做方差的东西。
让我们使用一些我们都熟悉的类型:
java.lang.Integer extends java.lang.Number extends java.lang.Object
协方差
在协变系统中,您可以编写:
Number x = new Integer();
但是您不能写:
Integer y = new Number();
您可能会猜到,java中的基本赋值都是协变的。但这不是唯一的方法。
Contravariance
在一个逆变系统中,您不能写:
Number x = new Integer();
但在另一面,这实际上有效:
Integer y = new Number();
不变性
这是死板的;在这一过程中,两者均无效。您唯一可以做的是:
Integer y = new Integer();
好的,那么泛型呢?
尽管Java是基本变量的协变变量,但泛型不是。泛型是对变的,协变的或不变的,具体取决于您编写泛型的方式。
- 协变量:
List<? extends Number> list = new ArrayList<Integer>(); // legal
- 变量:
List<? super Integer> list = new ArrayList<Number>(); // legal
- 不变式:
List<Integer> list = new ArrayList<Integer>(); // only integer will do here
您选择了不变式。所以只有ProcessorMechanics
会做;您的ProcessorMechanicsRoom
是子类,因此除非您的类型关系允许协方差,否则您不能这样做。将其设置为? extends
即可。
嗯,wtf?为什么?
因为...生活。这就是现实生活的方式。
想象一下没有。我可以这样做,然后破坏一切:
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)调用将检索不是整数的double值。幸运的是,以上内容并未编译;错误发生在标记的行上。那是..因为编译器不应该这样做。就其本质而言,泛型是不变的。
现在,协方差可以存在。例如,如果您有一种方法可以汇总对每个内部数字调用.intValue()
的结果,则可以编写:
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)
。
这是不变性的一个例子:
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表示。
对于列表,很简单:“ contravariance =加”(.add()
,.addAll()
等),“ covariance =读取”,“ invariance =两者都做”。对于其他泛型类型,可能不是那么简单。
大概如果您的ProcessorMechanics类只会“读”,那么您可以使其协变并编写:
public ProcessorMechanics(ObjectPool<? extends ProcessorMechanics<P,M,C>> pool) {...}