简体   繁体   English

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

[英]“Type mismatch” when using Java generics with wildcard

I have a strange problem using Generics in Java. 我在Java中使用泛型时遇到了一个奇怪的问题。 Generics are quite new to me, but I think I understand the basics. 泛型对我来说很新,但是我想我了解基本知识。

Please have a look at this piece of code: 请看一下这段代码:

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

Because the type of objects stored inside the quadtree-structure is not relevant for this method, I use a wildcard for the method signature, so that this method can be applied to all kinds of QuadTree's. 因为存储在四叉树结构内部的对象类型与该方法无关,所以我对方法签名使用通配符,因此该方法可以应用于各种QuadTree。

The method getChildren() returns the four childs of the node, stored inside the collection-class called Array ( implementation of Array ). 方法getChildren()返回该节点的四个子节点,存储在称为Array的集合类(Array的实现 )内。 I am sure the return type of getChildren() is indeed Array<QuadTree<?>> (even Eclipse says so inside the tooltip), but I still get an error on this line, telling me: 我确定getChildren()的返回类型确实是Array<QuadTree<?>> (即使Eclipse在工具提示中也这样说),但是我仍然在这行上得到一个错误,告诉我:

cannot convert from Array<QuadTree<capture#6-of ?>> to Array<QuadTree<?>>

Here comes the fun part: When I ask Eclipse for suggestions how to solve this, this is one of the suggestions: 这里是有趣的部分:当我向Eclipse请求如何解决此问题的建议时,这是建议之一:

Change type of 'children' to 'Array<QuadTree<?>>'

But it already is of this type! 但是它已经是这种类型了! It get's better: When I click on this suggestion, Eclipse changes this line to: 更好:当我单击此建议时,Eclipse将此行更改为:

Array<?> children = node.getChildren();

Of course, this destroys all the following code. 当然,这会破坏以下所有代码。

What the heck is going on here? 这里到底发生了什么? Could someone enlighten me, please? 有人可以启发我吗?

The problem is the method doesn't know it's the same QuadTree<?> (the ? could refer to different types in the same call). 问题在于方法不知道它是相同的 QuadTree<?>?可能在同一调用中引用不同的类型)。

The solution is to "type" the method, which locks in QuadTree<?> (and therefore ? ) to be the same type throughout the method. 解决的办法是“类型”的方法,它锁定在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);
        }
    }
}


? still means "anything", but it now the same "anything". 仍然表示“任何东西”,但现在却是相同的 “任何东西”。

In addition to Bohemian's answer, I want to point out that you can still have the same signature that you want (nobody needs to know that you are using this "T" type parameter, because it's an implementation detail. 除了Bohemian的答案,我想指出的是,您仍然可以拥有所需的签名(没有人知道您正在使用此“ T”类型参数,因为这是实现细节。

You can do that by making a wrapper method, with the original type signature, that calls the generic method with T. The call works due to capture. 您可以通过使用原始类型签名的包装器方法来实现,该方法使用T调用通用方法。该调用由于捕获而起作用。

private void drawQuadtreeBoxes_helper(QuadTree<?> node) {
    drawQuadtreeBoxes_helper_private(node);
}

private <T extends QuadTree<?>> void drawQuadtreeBoxes_helper_private(T node) {
    // code here ...
}

Of course, since the method in your example is private, you might not bother to do all this. 当然,由于示例中的方法是私有的,因此您可能不必费心做所有这一切。 But if it was a public API, it might be a good idea to do this, to abstract away the unnecessary implementation detail of the T. 但是,如果它是一个公共API,则最好这样做,以抽象出T不必要的实现细节。

If you do not care about type argument inside QuadTree simple remove everywhere from you code:) Just tried following code, compiler considers it as OK: 如果您不在乎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);
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM