繁体   English   中英

为什么以下代码对对象列表进行排序?

[英]Why does the following code sort the List of objects?

你能否解释为什么下面的代码按预期编译和打印[1,2,3,4]。 我正在使用Java 8。

List nums = Arrays.asList(4, 3, 2, 1);
Collections.sort(nums);
System.out.println(nums);

据我所知,这里创建了四个Integer实例。 每个列表条目都包含对Integer实例的Object引用。 由于Object类没有实现Comparable接口,因此Collections.sort应该抛出ClassCastException或类似的东西,因为它无法将Object引用强制转换为Comparable引用。

你能指出我错过了什么吗?

使用1,2,3,4,您将创建int文字。 在将它们传递给asList(T... a)它们被装入Integer对象,这些对象实现Comparablepublic final class Integer extends Number implements Comparable<Integer> ),因此您可以对它们进行排序。

更新

注释:是的,但List被声明为List,因此它是List<Object>的同义词,而不是List<Integer> ,而Object不实现Comparable

答:您没有为列表指定泛型类型, Collections.sort()方法仅检查对象的类是否扩展Comparable 如果列表没有类型,你的编译器应该只给你一个警告,一切都应该正常工作,因为Integer是可比的。

排序方法的源代码

public static <T extends Comparable<? super T>> void sort(List<T> list) {
    Object[] a = list.toArray();
    Arrays.sort(a);
    ListIterator<T> i = list.listIterator();
    for (int j=0; j<a.length; j++) {
        i.next();
        i.set((T)a[j]);
    }
}

更新

执行这段代码,看看如果类没有实现Comparable会发生什么。

public class Test
{
    public static void main(String[] args)
    {
        List objs = new ArrayList<>();
        objs.add(new Test());
        objs.add(new Test());
        Collections.sort(objs);
    }
}

Comparable第290行中完成的ComparableTimSort.class将失败!

Exception in thread "main" java.lang.ClassCastException: src.Test cannot be cast to java.lang.Comparable
at java.util.ComparableTimSort.countRunAndMakeAscending(Unknown Source)
at java.util.ComparableTimSort.sort(Unknown Source)
at java.util.ComparableTimSort.sort(Unknown Source)
at java.util.Arrays.sort(Unknown Source)
at java.util.Collections.sort(Unknown Source)
at src.Test.main(Test.java:14)

引用的类型与它指向的对象的实际类型之间存在很大差异。

Integer i = 42;
Object o = i;
System.out.println(i.getClass());
System.out.println(o.getClass());

输出:

class java.lang.Integer
class java.lang.Integer

io指向运行时类型始终为Integer的对象(或值)。 使用更一般类型的引用指向对象不会以任何方式影响其属性或行为。 这就是多态在Java中的工作原理。

因此,这两项任务都有效:

Comparable<Integer> c1 = i;
Comparable<Integer> c2 = (Comparable<Integer>) o;

即使您使用的是原生整数,autobox也会自动将其转换为java.lang.Integer(实现可比较)。 http://docs.oracle.com/javase/8/docs/api/java/lang/Integer.html

实际上这是一个铸造问题。 最初创建一个整数数组,然后您已转换为列表。 我希望这个对你有所帮助。

    Integer[] number=new Integer[]{4,3,2,1};
    Collections.sort(Arrays.asList(number));
    System.out.println(Arrays.asList(number));

缺少的部分是类型擦除。

Java编译为JVM字节码,JVM字节码没有泛型概念。 因此,在运行时, ListList<Comparable>List<Object>完全相同。 如果您的代码曾经包含该信息(您的代码没有),那么在编译代码时它将被删除。

这意味着在运行时, List<Object>List<Comparable>之间没有区别,除了它们包含的实际元素(因此,它也意味着如果你的List包含任何元素,那么就没有办法了告诉它是什么类型的List )。

Collections.sort能够对其元素全部实现Comparable并且彼此具有Comparable任何List进行排序。 由于List包含实现Comparable Integer ,因此Collections.sort能够对其进行排序。

也许是令人困惑的,出于历史原因,这不是阵列的真实情况。 Comparable[]Object[]是完全不同的类型。 原则上,这意味着Java的数组排序方法可能会拒绝对Object[]数组进行排序,正如您所期望的那样。 实际上它们没有, Arrays.sort接受Object[]数组,类似于Collections.sort

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM