【问题标题】:Why can't we capture wildcards for the method with two parameters?为什么我们不能为带有两个参数的方法捕获通配符?
【发布时间】:2015-06-08 07:28:20
【问题描述】:

that问题有关。

我知道通配符捕获。例如,以下内容可用于反转列表:

public static void reverse(List<?> list) { rev(list); } //capturing the wildcard
private static <T> void rev(List<T> list) {
    List<T> tmp = new ArrayList<T>(list);
    for (int i = 0; i < list.size(); i++) {
        list.set(i, tmp.get(list.size()-i-1));
    }
}

现在我正在尝试为这种情况写同样的东西:

private int compare (Comparable<?> upper, Comparable<?> lower){
    return comp(upper, lower);  //The method comp(Comparable<T>, Comparable<T>) is not applicable for the arguments (Comparable<capture#5-of ?>, Comparable<capture#6-of ?>)
}

private <T> int comp(Comparable<T> upper, Comparable<T> lower){
    return upper.compareTo((T) lower);
}

我希望它也能很好地编译。是否可以通过这种方式为具有两个或多个参数的方法捕获通配符?

【问题讨论】:

    标签: java generics wildcard


    【解决方案1】:

    因为,正如我在回答您的另一个问题时所说,编译器无法知道这两个 ? 代表相同的类型。

    两个? 分别代表某种未知类型。 compare 方法需要两个 Comparable 对象用于相同类型的 T。如果从comp 方法中调用compare,编译器无法确定这两个? 代表相同的类型。

    【讨论】:

    • 但是如果我们用 raw 替换泛型呢?我们可能会遇到什么麻烦?
    • 如果您使用原始类型,编译将通过,但是,您会收到警告说在运行时可能会发生 ClassCastException。泛型有助于避免此类错误。
    • 当您使用原始类型时,编译器会进入向后兼容模式,类型检查较少。但是你不应该使用原始类型;见:What is a raw type and why shouldn't we use it?
    【解决方案2】:

    在这个方法中

    private <T> int comp(Comparable<T> upper, Comparable<T> lower){
        return upper.compareTo((T) lower);
    }
    

    这两个参数共享相同的类型参数。

    同时,对于另一种方法,情况并非如此:

    private int compare (Comparable<?> upper, Comparable<?> lower){
        return comp(upper, lower); 
    }
    

    在这里,编译器没有证据表明 upperlower 的类型参数是相同的,这就是拒绝为编译开绿灯的原因。

    如果您希望这两种方法共享相同的类型参数,您可以将类型参数设置为class-scoped。例如:

    public class YourClass<T> {
         private int comp(Comparable<T> upper, Comparable<T> lower){
             return upper.compareTo((T) lower);
         }
    
         private int compare (Comparable<T> upper, Comparable<T> lower){
             return comp(upper, lower); 
         }
    }
    

    另一个选项(如果您不喜欢第一个选项)是为comp()compare() 的类型参数引入一个相同的上限。例如:

    private <T extends SomeSuperClass> int comp(Comparable<T> upper, Comparable<T> lower){
        return upper.compareTo((T) lower);
    }
    
    private <T extends SomeSuperClass> int compare (Comparable<T> upper, Comparable<T> lower){
        return comp(upper, lower); 
    }
    

    此外,如果您想避免在 comp() 方法中进行强制转换,您可以这样做:

    public class YourClass<T extends SomeSuperClass & Comparable<T>> {
         private int comp(T upper, T lower){
             return upper.compareTo(lower);
         }
    
         private int compare (T upper, T lower){
             return comp(upper, lower); 
         }
    }
    

    【讨论】:

    • 所以我们可以将 socnd 类型参数添加到 compare 方法中。但它看起来很不安全。我们可能会遇到什么样的问题?
    • 我的意思是private &lt;T, M&gt; int comp(Comparable&lt;T&gt; upper, Comparable&lt;M&gt; lower)
    • 如果你想在方法之间共享类型参数,要么将类型参数设置为类范围,要么为它们引入相同的上限。
    • 好主意。这完全符合我的条件。太棒了。我的意思是,你的第一个解决方案。
    猜你喜欢
    • 2014-04-07
    • 1970-01-01
    • 2017-11-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-06
    • 2016-08-31
    • 1970-01-01
    相关资源
    最近更新 更多