好吧,理想情况下,您不应该将 aPriQMsgPayload<Integer>
与 a进行比较PriQMsgPayload<String>
——因为 aPriQMsgPayload<Integer>
实现了Comparable<PriQMsgPayload<Integer>>
,因此它的compareTo
方法需要 a PriQMsgPayload<Integer>
,所以它不期望 a PriQMsgPayload<String>
。
在编译时和运行时尝试执行此操作时会发生什么,取决于您的优先级队列类是如何声明的,以及它是如何工作的。您没有告诉我们您正在使用哪种优先级队列实现。
假设您有一个通用的优先级队列类,声明如下:
class MyPriorityQueue<E extends Comparable<? super E>> { ... }
即它要求其类型参数与自身相当。那么就不可能声明一个可以同时插入PriQMsgPayload<Integer>
和插入的优先级队列PriQMsgPayload<String>
;因为 egMyPriorityQueue<PriQMsgPayload<?>>
不会被允许,因为PriQMsgPayload<?>
不满足界限。
如果您使用java.util.PriorityQueue
,则问题是PriorityQueue
该类(以及TreeSet
andTreeMap
等)不是类型安全的。您可以创建一个new PriorityQueue<Object>()
,然后将任何类型的对象插入其中(完全不可比较的对象),并且它不会在编译时捕获任何内容,仅在运行时失败(或者它可能碰巧工作,具体取决于对象的类型)。
在这种情况下,运行时会发生什么?好吧,在类型擦除之后,在运行时,该类等价于:
public class PriQMsgPayload implements Comparable {
// ....
public int compareTo(Object another) {
return compareTo((PriQMsgPayload)another);
}
public int compareTo(PriQMsgPayload another) {
return mMsgNum.compareTo(another.mMsgNum);
}
}
它只是比较整数,因此在这种情况下,在运行时,它会正常工作。
为什么PriorityQueue
类型不安全?好吧,如果您查看该类,它被设计为以两种方式之一使用:您可以提供一个 custom Comparator
,或者它将使用对象的“自然排序”。如果是后者,您应该提供与它们自己相当的东西,但这在编译时不会以任何方式强制执行。因为您可以将它与适用于任何类型的自定义比较器(方式#1)一起使用,所以它们不能像我们在MyPriorityQueue
上面所做的那样对类的类型参数设置任何界限。
实际上,有一种方法可以使PriorityQueue
类型安全,并且仍然能够支持自定义比较器和自然排序模式。只需删除使用自然排序的构造函数(留下使用比较器的构造函数,因为它们是类型安全的),而是用工厂方法替换它们。例如,构造函数
PriorityQueue(int initialCapacity)
可以用工厂方法代替
public static <T extends Comparable<? super T>> PriorityQueue<T> construstUsingNaturalOrdering(int initialCapacity) {
return new PriorityQueue<T>(initialCapacity, new NaturalOrderingComparator<T>());
}
这样,绑定在工厂方法上的泛型可确保只能为与其自身可比的类型构建自然排序优先级队列。我不知道为什么 Java 库设计者不这样做。