java—为什么集合的两个api的输入参数存在泛型不匹配

f4t66c6m  于 2021-06-29  发布在  Java
关注(0)|答案(4)|浏览(294)

我在研究collections类的泛型方法

public static <T> void sort(List<T> list, Comparator<? super T> c) {
        list.sort(c);
}

另一种方法是

public static <T> int binarySearch(List<? extends T> list, T key, Comparator<? super T> c) {
        if (c==null)
            return binarySearch((List<? extends Comparable<? super T>>) list, key);

        if (list instanceof RandomAccess || list.size()<BINARYSEARCH_THRESHOLD)
            return Collections.indexedBinarySearch(list, key, c);
        else
            return Collections.iteratorBinarySearch(list, key, c);
    }

我的问题是为什么排序方法只针对 List<T> 不是为了 List<? extends T> 因为二进制搜索是为 List<? extends T> ?

mm5n2pyu

mm5n2pyu1#

只有当列表是同质的时,对列表进行排序才有意义;如果一个人在整理一堆文件,如果你把一整本书放在一起,它就会突然崩溃。
如果每个项目都是可比较的,那么搜索列表是有意义的。如果你能定义一张a4纸和一本小说之间的关系,那么你就可以在它们之间进行搜索。

kxkpmulp

kxkpmulp2#

我给我贴出的问题,我觉得更准确的答案。

public static <T> void sort(List<T> list, Comparator<? super T> c) {
        list.sort(c);
}

public static <T> void sort(List<? extends T> list, Comparator<? super T> c) {
        list.sort(c);
}

都是一样的。因为我们是这样调用上述方法的

ArrayList<Employee> list = new ArrayList<>();
list.add(new Manager(106,true));
list.add(new Manager(102,true));
sort(list, (p1, p2) -> 
p1.getEmployeeId().compareTo(p2.getEmployeeId()));

`T` argument in `sort()` will be considered as Manager in this case

ArrayList<Employee> list = new ArrayList<>();
 list.add(new Employee(106,true));
 list.add(new Employee(102,true));
 sort(list, (p1, p2) -> 
 p1.getEmployeeId().compareTo(p2.getEmployeeId()));

`T` argument in `sort()` will be Employee in this case.

我们在写作上一无所获 List<? extends T>sort() . 一个真实的单词示例如果有两个球,那么我们可以只使用一个词,第一个球比第二个大,或者第一个球比第二个小。如果我们有三个球,只有一件事是可能的,要么大要么小,我们可以说,第一个球比第二个球小,第三个球比第二个球大,那么两个词可以用得越来越小。
我们需要一些基地 T 那我们可以用任何一个 ? extends T 或者 ? super T 或者两者兼而有之,比如我在上面发布的二进制搜索方法签名。
jdk还提供了三签名的排序方法,但方式不同

public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
    public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray();
        if ((size = elementData.length) != 0) {
            // c.toArray might (incorrectly) not return Object[] (see 6260652)
            if (elementData.getClass() != Object[].class)
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {
            // replace with empty array.
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }

@Override
    @SuppressWarnings("unchecked")
    public void sort(Comparator<? super E> c) {
        final int expectedModCount = modCount;
        Arrays.sort((E[]) elementData, 0, size, c);
        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
        modCount++;
    }

以上 ArrayList<E> 可以是 E 类型,它可以接受 Collection<? extends E> c 并且可以使用 Comparator<? super E> c . 根据解释我们还有三个球
它可以是什么类型的元素
收藏<?扩展e>它可以接受列表
比较器<?它可以通过这样的比较器进行排序

utugiqy6

utugiqy63#

在sort函数中,只有两种不同的类型:列表类型和比较器类型。 T 中元素的类型 List ,和 ? super T 的类型 Comparator . 你不会通过添加 List<? extends T> 在那里。
binarySearch 有三种类型: T 表示对象的类型 key 待搜查, ? extends T 是列表的类型,并且 ? super T 是比较器的类型。

olhwl3o2

olhwl3o24#

逻辑是相反的。如果要对泛型类型的元素列表进行排序 T ,为什么要接受一个更通用的比较器类型,它可以是 T ?
答案是需要 Comparator<T> 将具有不必要的限制性,例如,阻止重用现有的比较器。这是因为泛型类型 TComparator<T> 控制对象的类型 compare 方法中传递要比较的对象。但是,由于可以始终将子类型的对象指定给超类型的变量,因此使用感兴趣元素的超类型的比较器是类型安全的。
比如说你有一节课 Person :

public class Person {

public int age() { /* ... */ }

public static Comparator<Person> byAge() {
    return (p1, p2) -> p1.age() - p2.age();
}

还有一节课 Programmer :

class Programmer extends Person { /* ... */ }

您可以重用“person comparator”对程序员列表进行排序:

List<Programmer> programmers = new ArrayList<>();
// Initialize list
Collections.sort(programmers, byAge());

如果你需要一个 Comparator<Programmer> 给你的名单排序。

相关问题