java - 在泛型声明中使用 "? extends"时,能否避免 Java 中的参数不匹配?

标签 java generics inheritance

我正在尝试创建一个函数来处理(可比较的)元素的排序列表。因此,我使用通用的 <T extends List<? extends Comparable>> ,只要我不需要任何需要 <? extends Comparable> 的特定于列表的操作,它就可以工作作为输入。但是在下面的代码片段中(最简单的例子:计算两个排序列表的交集)行 C.add((Comparable)(A.get(posA)));被编译器拒绝,声称 add需要争论 ? extends Comparable ,这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)是有效类型 ? extends Comparable ?显然转换不起作用,我希望例程接受并返回任意可比较项(整数、字符串、自定义对象等)的列表

最佳答案

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

事实上,如果您了解泛型在 Java 中的工作原理,事情并没有那么复杂。
这可以帮助你:

根据您的实际代码,以下是您应该考虑的主要事项: 1) 不要使用原始类型,例如 List<? extends Comparable>> . Comparable是一个泛型类。
2) 除了 null 之外,您不能添加任何内容在声明的列表中 List<? extends Foo> ,即使用上限通配符。最后一个允许使 List 协变:接受 Foo 和任何子类但具有先前的限制。所以你不想使用它。
3) 你可以实例化一个泛型 ArrayList无需声明泛型方法类型 T对于 ArrayList .使用 T对于 Comparable type 会让事情变得更简单。
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;
}

That was my original approach, but the problem here is that not every that the intersection of two non-ArrayList Lists will be an ArrayList here.

如果声明 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
}

关于java - 在泛型声明中使用 "? extends"时,能否避免 Java 中的参数不匹配?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52454297/

相关文章:

c# - 有没有办法得到 typeof Func<T, bool>?

java - 这个沮丧的:(B)super.克隆()如何工作?

scala - 非法继承,父类(super class) X 不是 mixin 特征 Z 的父类(super class) Y 的子类 - Scala

java - 仅当所有文件都可删除时才删除文件 - 放过无辜者

java - 我的 add 方法是否做了太多工作?

java - 如何创建一个可以构建多种 Java 对象的 Builder?

JTextArea 中用于控制字符的 Java 图像

java - 实例不工作?

c# - 在树层次结构中具有深度限制的通用深度克隆

c++ - Qt/C++ 从 QPolygonF 继承为 QList 项