将Java泛型与通配符一起使用时,“类型不匹配”

时间:2012-07-06 18:46:56

标签: java generics

我在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();

当然,这会破坏以下所有代码。

这到底是怎么回事?有人可以开导我吗?

3 个答案:

答案 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);
        }
    }
}