简体   繁体   English

如何对兼容的通配符进行不同的捕获?

[英]How can I make different captures of a wildcard compatible?

I'm trying to make a generic class with one type parameter, class MyClass<E> , that has a class variable of a second generic class with two type parameters, SecondClass<V, E> . 我正在尝试使用一个类型参数class MyClass<E>创建泛型类,它具有第二个泛型类的类变量,其中包含两个类型参数SecondClass<V, E> Since for my code it really doesn't matter what the type of V is, I declare the type of that variable as SecondClass<?, E> var . 因为对于我的代码而言, V的类型无关紧要,我将该变量的类型声明为SecondClass<?, E> var At some point in the implementation of MyClass I call a method on var that returns a V, public V foo(E e) , and then I pass this object of type V to another method of var, public int bar(V v) . 在MyClass实现的某个时刻,我在var上调用一个返回V, public V foo(E e) ,然后将这个V类型的对象传递给另一个var, public int bar(V v) However, this doesn't compile because of reasons I only vaguely understand, but I believe it is explained in here . 然而,这并不编译的,因为我的原因只是隐约知道,但我相信它在说明这里

Apparently, the capture-of-? 显然,捕获了? returned by foo is different from the the capture-of-? foo返回的不同于捕获的? required by bar. 酒吧需要。 But why? 但为什么? Whatever the actual type of V is, it must be the same for both methods, since they are invoked on the same instance. 无论V的实际类型是什么,它对于两种方法都必须相同,因为它们是在同一实例上调用的。 What am I missing here? 我在这里错过了什么?

Ultimately, what I would like to know is this: what do I need to change in order to make the code compile, without adding V to the type parameters of MyClass? 最后,我想知道的是:为了使代码编译,我需要更改什么,而不将V添加到MyClass的类型参数? (I don't want to enforce users of MyClass to specify the type of V since it shouldn't matter) (我不想强制MyClass的用户指定V的类型,因为它应该无关紧要)


To give you a more concrete example, here's a simplified version of what I'm working on. 为了给你一个更具体的例子,这里是我正在研究的简化版本。 As you may already have guessed by the type parameters, it concerns graphs. 正如您可能已经通过类型参数猜测的那样,它涉及图形。 MyClass translates to EdgePainter and SecondClass translates to Graph . MyClass转换为EdgePainterSecondClass转换为Graph With this code, the compile error is in the first line of EdgePainter.getColor(E) . 使用此代码,编译错误位于EdgePainter.getColor(E)的第一行。

class Graph<V, E>
{

    public V getTarget(E edge)
    {
        return null;
    }

    public int getInDegree(V vertex)
    {
        return 0;
    }

}

class EdgePainter<E>
{

    private static final Color COLOR_FOR_MANY_EDGES = Color.RED;
    private static final Color COLOR_FOR_FEW_EDGES = Color.BLUE;

    private Graph<?, E> graph;

    public EdgePainter(Graph<?, E> aGraph)
    {
        graph = aGraph;
    }

    public Color getColor(E edge)
    {
        // My compiler says:
        // The method getInDegree(capture#3-of ?) in the type
        // Graph<capture#3-of ?,E> is not applicable for the arguments
        // (capture#4-of ?)
        int degree = graph.getInDegree(graph.getTarget(edge));
        if (degree > 10)
            return COLOR_FOR_MANY_EDGES;
        else
            return COLOR_FOR_FEW_EDGES;
    }

}

You can capture the wildcard by invoking a generic method. 您可以通过调用泛型方法捕获通配符。

public Color getColor(E edge) {
    return getColorInternal(graph, edge);
}
private <X> Color getColorInternal(Graph<X, E> g, E e) {
    int degree = g.getInDegree(g.getTarget(e));
    // ...
}

This is a typical scenario. 这是典型的情况。 You need a type argument for the implementation, but want to hide it from API users. 您需要实现的类型参数,但希望将其隐藏在API用户中。 If many methods are affected it can be helpful to define a separate, perhaps nested, class EdgePainterInternal . 如果许多方法受到影响,定义一个单独的,可能是嵌套的类EdgePainterInternal This internal implementation has the second type parameter G and the publicly visible implementation EdgePainter delegates all calls to an instance of EdgePainterInternal . 此内部实现具有第二个类型参数G和公开可见的实现EdgePainter所有调用委托给EdgePainterInternal实例。

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

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