为什么需要通配符捕获?

时间:2019-03-10 09:20:14

标签: java generics wildcard-capture

在官方教程#Wildcard CaptureWildcard Capture and Helper Methods中,其易于理解的演示如下:

public class WildcardFixed {

    void foo(List<?> i) {
        fooHelper(i);
    }
    private <T> void fooHelper(List<T> l) {
        l.set(0, l.get(0));
    }
}

我还阅读了StackOverflow上一些有关通配符捕获的文章,但是当我尝试将其用作

public static <T> void addToSet(Set<T> s, T t) {
// I was hoping the type inference will infer the T to String
}

private static <T> Set<T> setWrapper(Set<T> theSet) {
    return theSet;
}

public static void testUnboundedWildcard() {
    Set<?> unknownSet = new HashSet<String>();

    // ------> here lies the compile error <-------
    HelloWorld.<String>addToSet(setWrapper(unknownSet), "abc");
}

显示编译错误

Error:(52, 47) java: incompatible types: inferred type does not conform to equality constraint(s)
    inferred: java.lang.String
    equality constraints(s): java.lang.String,capture#1 of ?

我以为我可以捕获通配符并将其作为generic method来处理,但我完全错了。

我的困惑

  1. 为什么我使用 Wildcard Capture 的代码无法正常工作?
  2. 如果它无法正常工作,那么为什么恰好我们需要它?可以找到任何特定的情况吗?

1 个答案:

答案 0 :(得分:2)

  

为什么我们确实需要它?可以找到任何特定的情况吗?

当您只需要使用基本类型并且真的不在乎泛型时,就可以使用它。

例如,您可以有一个方法

boolean hasTooManyElements(Collection<?> data){
    return data.size() > 100;
}

没有通配符,您将不得不(没有充分的理由)将这种方法限制为仅适用于特定类型的Collections。

请注意,通配符仍然可以绑定:

boolean hasEmptyText(Collection<? extends CharSequence> data) {
   return data.exists(x -> x.isEmpty()); 
   // you can call `isEmpty` because of the bounded wildcard
}

您也可以通过使方法通用来表达这一点(但是,如果您不打算在任何地方使用类型T的话,没有什么意义。

<T> boolean hasTooManyElements(Collection<T> data);

在以下情况下,您希望拥有<T>

// limit the return type
<T> T getRandomElement(Collection<T> data);
// or, more flexible
<T> T getRandomElement(Collection<? extends T> data);

// make sure the two inputs have the same generic type
<T> boolean areEqual(Collection<T> one, Collection<T> two);