我正在实现一个通用的BST,它不允许重复。我已经创建了一个Node
类,它具有以下定义:
class Node<T extends Comparable<T>> implements Comparable<Node<T>>{
private T value;
// other stuff
}
使用,我基本上希望与某个节点关联的值与相同类型的其他值具有可比性。然后我也有下面的compareTo
方法:
@Override
public int compareTo(Node<T> o) {
return value.compareTo(o.value);
}
现在,在我的BST的实现中,我有一个关于参数接受的问题。BST有以下定义:
public class BinaryTreeSet<T extends Comparable<T>> {
private Node<T> root;
// other stuff
}
您可以看到,我要求根的泛型类型与具有相同泛型类型的其他值具有可比性,即T extends Comparable<T>
。这似乎都没问题,直到我的add
方法的实现,它具有以下签名:
public void add(Node<T> n) {...}
没有什么可疑的(至少对我来说),但是如果我有以下代码:
BinaryTreeSet<String> t = new BinaryTreeSet<>();
t.add(new Node(12)); // Adding a raw Node (whose value is actually an integer)
它实际上编译了,但它不应该编译,因为我正在实例化BinaryTreeSet
的String
s,所以我不应该能够向树中添加数字。
我做错了什么,为什么?在这些情况下,我如何使它不编译?
没有办法防止这种情况,因为Java在运行时不保留泛型类型信息。当程序执行时,value
是Object
,因此可以同时保存Integer
和String
。
实践中的解决方案是简单地禁止代码中的原始类型。几乎没有理由在现代Java应用程序中使用它们,只有在经过良好测试且可见性受限的库代码中才使用它们。从不应用逻辑。如果您应该使用原始类型,javac
已经打印了一个警告,您最好不要忽略它们。
正如ApproachingDarknessFish所指出的,如果你使用原始类型,你可以通过这样调用它来强制javac
失败:
javac -Xlint:rawtypes -Werror ....