1

我在 Java 中使用泛型有一个奇怪的问题。泛型对我来说很新,但我想我了解基础知识。

请看一下这段代码:

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

因为存储在四叉树结构中的对象类型与此方法无关,所以我使用通配符作为方法签名,以便此方法可以应用于各种四叉树。

getChildren() 方法返回节点的四个子节点,存储在名为 Array 的集合类(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();

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

这到底是怎么回事?有人可以启发我吗?

4

3 回答 3

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


?仍然意味着“任何东西”,但它现在是相同的“任何东西”。

于 2012-07-06T18:52:07.963 回答
1

除了 Bohemian 的回答,我想指出你仍然可以拥有你想要的相同签名(没有人需要知道你正在使用这个“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 的不必要的实现细节。

于 2012-07-07T01:34:57.453 回答
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);
        }
    }
}
于 2012-07-06T19:06:06.573 回答