java-编译器忽略的泛型类型
最近我偶然发现了一个看起来不合逻辑的泛型的边缘情况。
我有一个简单的界面,它返回一个孩子的列表:
public interface INode<C extends INode> {
List<C> getChildren();
}
我希望如果 INode 类型在没有定义 C 类型的情况下被引用,C 类型将被编译器推断为 INode。换句话说,在下面的代码中:
public void retrieveChildren(INode node) {
var children = node.getChildren();
}
儿童将被推断为List<INode>类型。相反,它只是普通的 List。
值得注意的是,类型推断在 INode 方法返回单个元素的情况下按预期工作,因此当此接口时:
public interface INode<C extends INode> {
C getFirstChild();
}
用于以下方法:
public void retrieveFirstChild(INode node) {
var firstChild = node.getFirstChild();
}
firstChild 被正确地推断为 INode。
jdk 有这样工作的理由吗?另外,是否有一种干净的方法可以为返回的列表强制使用 C 类型?
非常感谢。
回答
儿童将被推断为 List< INode> 类型。相反,它只是普通的 List。
一旦你使用原始类型,它就会感染一切。INode具有 typeargs,并且在您的签名 ( retrieveFirstChild) 中,您使用它原始,这意味着涉及任何泛型与该变量的所有交互也是原始的。
解决方案是永远不要使用 raw(编译器警告,你应该注意这些警告!):
public void retrieveFirstChild(INode<?> node) {
// note the <?> up there!
var firstChild = node.getFirstChild();
}
现在 firstChild 的类型是INode,正如预期的那样。