在泛型声明中使用“?extends”时,是否可以避免Java中的参数不匹配?

时间:2018-09-22 06:55:55

标签: java generics inheritance

我正在尝试创建一个处理(可比较)元素的排序列表的函数。因此,我使用的是通用的<T extends List<? extends Comparable>>,只要我不需要任何需要使用<? extends Comparable>作为输入的特定于列表的操作,它就可以工作。但是在下面的代码片段中(最简单的示例:计算两个排序列表的交集),C.add((Comparable)(A.get(posA)));行被编译器拒绝,声称add需要参数? extends Comparable,{{1 }}显然不是。

Comparable

我应该如何告诉编译器public static <T extends List<? extends Comparable>> T intersect (T A, T B) { T C = (T) A.getClass().newInstance(); int posA = 0; int posB = 0; while(posA<A.size()&&posB<B.size()) { if (A.get(posA).compareTo(B.get(posB))>0) posB++; else if (A.get(posA).compareTo(B.get(posB))<0) posA++; else if (A.get(posA).equals(B.get(posB))) { C.add((Comparable)(A.get(posA))); posA++; posB++; } } return C; } 是有效类型A.get(posA)?显然,转换不起作用,我希望例程接受并返回任意可比较对象(整数,字符串,自定义对象等)的列表

2 个答案:

答案 0 :(得分:4)

您是否没有注意到代码中所有不安全的类型语句,其中多个不安全的类型转换?
你真的有很多。这通常意味着整体方法不是正确的方法。

实际上,如果您学习泛型在Java中的工作原理,事情并不会那么复杂。
那可以帮助您:

以下是根据实际代码应考虑的主要事项: 1)不要使用诸如List<? extends Comparable>>之类的原始类型。 Comparable是泛型类。
2)您不能在声明为null的列表中添加List<? extends Foo>以外的任何内容,即使用上限通配符。最后一个允许使List成为协变量:接受Foo和任何子类,但有先前的限制。所以你不想使用它。
3)您可以实例化通用ArrayList,而无需声明T的通用方法类型ArrayList。将T用于Comparable类型将使事情变得更加简单。
4)您要尽可能避免反射。

按照这些想法,您可以编写如下代码:

public static <T extends Comparable<T>> List<T> intersect (List<T> A, List<T> B) {
    List<T> list = new ArrayList<>();       
    int posA = 0;
    int posB = 0;
    while(posA<A.size()&&posB<B.size()) {
        if (A.get(posA).compareTo(B.get(posB))>0) posB++;
        else if (A.get(posA).compareTo(B.get(posB))<0) posA++;
        else if (A.get(posA).equals(B.get(posB))) {
            list.add(A.get(posA));
            posA++; posB++;
        }
    }
    return list;
}
  

那是我最初的方法,但是这里的问题是,不是每一个   两个非ArrayList列表的交集将是一个ArrayList   在这里。

如果您为参数声明List,则在编译时将不知道List的类型。因此,您不可避免地要进行不安全的转换。
例如:

@SuppressWarnings("unchecked")
public static <T extends Comparable<T>, L extends List<T>> L intersect(L A, L B)  {

    if (A.getClass() != B.getClass()) {
        throw new IllegalArgumentException("not same type between ...");
    }
    List<T> list = A.getClass()
                    .newInstance(); // uncheck

    int posA = 0;
    int posB = 0;
    while (posA < A.size() && posB < B.size()) {
        if (A.get(posA)
             .compareTo(B.get(posB)) > 0)
            posB++;
        else if (A.get(posA)
                  .compareTo(B.get(posB)) < 0)
            posA++;
        else if (A.get(posA)
                  .equals(B.get(posB))) {
            list.add(A.get(posA));
            posA++;
            posB++;
        }
    }
    return (L) list; // uncheck
}

答案 1 :(得分:1)

这是一个典型的泛型问题。

您说的是您接受扩展Comparable的所有对象列表。

因此,另一种方法将List传递给您的方法将是完全可以的。

当然,即使扩展了Comparable,也不应允许您在代码中向该列表添加数字!

您可以通过在方法签名中添加另一个通用参数而不是“?”来解决此问题。然后,您可以在代码中强制转换为该参数。