我在Java中使用Generics时遇到了一个奇怪的问题。泛型对我来说很新,但我认为我理解基础知识。
请看一下这段代码:
private void drawQuadtreeBoxes_helper(QuadTree<?> node) {
if (node == null)
return;
Vector3 min = node.bbox.min;
Vector3 max = node.bbox.max;
// Draw the boxes (...)
if (node.hasChildren()) {
Array<QuadTree<?>> children = node.getChildren(); // ERROR HERE
for (QuadTree<?> child : children) {
drawQuadtreeBoxes_helper(child);
}
}
}
因为存储在四叉树结构中的对象类型与此方法无关,所以我使用通配符作为方法签名,以便此方法可以应用于所有类型的QuadTree。
方法getChildren()返回节点的四个子节点,存储在名为Array(implementation of Array)的集合类中。我确信getChildren()的返回类型确实是Array<QuadTree<?>>
(即使Eclipse在工具提示中也这么说),但我仍然在这一行上出错,告诉我:
cannot convert from Array<QuadTree<capture#6-of ?>> to Array<QuadTree<?>>
以下是有趣的部分:当我向Eclipse询问如何解决这个问题时,这是其中一个建议:
Change type of 'children' to 'Array<QuadTree<?>>'
但它已经是这种类型了!它变得更好:当我点击这个建议时,Eclipse会将此行更改为:
Array<?> children = node.getChildren();
当然,这会破坏以下所有代码。
这到底是怎么回事?有人可以开导我吗?
答案 0 :(得分:4)
问题是该方法不知道相同 QuadTree<?>
(?
可以在同一个调用中引用不同的类型)。
解决方案是“键入”该方法,该方法在整个方法中将QuadTree<?>
(因此?
)锁定为相同的类型。
private <T extends QuadTree<?>> void drawQuadtreeBoxes_helper(T node) {
if (node == null)
return;
Vector3 min = node.bbox.min;
Vector3 max = node.bbox.max;
// Draw the boxes (...)
if (node.hasChildren()) {
Array<T> children = node.getChildren(); // ERROR HERE
for (T child : children) {
drawQuadtreeBoxes_helper(child);
}
}
}
?
仍然意味着“任何事情”,但现在相同“任何事情”。
答案 1 :(得分:1)
除了波西米亚的回答,我想指出你仍然可以拥有你想要的相同签名(没有人需要知道你正在使用这个“T”类型参数,因为它是一个实现细节。
你可以通过创建一个带有原始类型签名的包装器方法来实现这一点,该方法使用T调用泛型方法。该调用由于捕获而起作用。
private void drawQuadtreeBoxes_helper(QuadTree<?> node) {
drawQuadtreeBoxes_helper_private(node);
}
private <T extends QuadTree<?>> void drawQuadtreeBoxes_helper_private(T node) {
// code here ...
}
当然,由于您示例中的方法是私有的,您可能不会费心去做所有这些。但如果它是一个公共API,那么这样做可能是一个好主意,以抽象出T的不必要的实现细节。
答案 2 :(得分:0)
如果你不关心QuadTree中的类型参数,那么从你的代码中删除无处不在:)只是尝试了下面的代码,编译器认为它没问题:
private void drawQuadtreeBoxes_helper(QuadTree node) {
if (node == null)
return;
Vector3 min = node.bbox.min;
Vector3 max = node.bbox.max;
// Draw the boxes (...)
if (node.hasChildren()) {
Array<QuadTree> children = node.getChildren();
for (QuadTree child : children) {
drawQuadtreeBoxes_helper(child);
}
}
}