Reputation: 211
Could you please explain why the following code compiles and prints [1, 2, 3, 4], as expected. I'm using Java 8.
List nums = Arrays.asList(4, 3, 2, 1);
Collections.sort(nums);
System.out.println(nums);
As I understand, four Integer instances is created here. Each list entry contains an Object reference to an Integer instance. Since the Object class doesn't implement the Comparable interface, then Collections.sort should throw ClassCastException or something like this because it cannot cast Object references to Comparable references.
Could you please point out what I'm missing?
Upvotes: 17
Views: 1479
Reputation: 3307
The missing piece here is type erasure.
Java compiles to JVM bytecode, and JVM bytecode has no concept of generics. So at runtime, a List
is precisely the same as a List<Comparable>
or a List<Object>
. If your code ever contained that information (which your code doesn't), then it is erased when your code is compiled.
This means that at runtime, there's no difference between a List<Object>
and a List<Comparable>
, other than the actual elements they contain (as a consequence, it also means that if your List
contains no elements, then there's no way of telling what sort of List
it was meant to be).
Collections.sort
is able to sort any List
whose elements all implement Comparable
, and are comparable with each other. Since your List
contains Integer
s, which implement Comparable
, Collections.sort
is able to sort it.
Perhaps confusingly, this isn't true of arrays, for historical reasons. Comparable[]
and Object[]
are completely different types. In principle, this means that Java's array sorting methods could refuse to sort Object[]
arrays, as you might expect. In practice they do not, and Arrays.sort
accepts Object[]
arrays, analogously to Collections.sort
.
Upvotes: 1
Reputation: 6887
With 1,2,3,4 you are creating int
literals. While passing them to asList(T... a)
they get boxed into Integer
objects which implements Comparable
(public final class Integer extends Number implements Comparable<Integer>
), so you can sort them.
Update
Comment: Yes, but the List is declared as List, so it's the synonym to List<Object>
, not List<Integer>
, and Object
doesn't implement Comparable
.
Answer: You do not specify a generic type for the list and the Collections.sort()
method only checks if the object's class extends Comparable
. If the list has no type, your compiler should only give you a warning and everything should work fine since Integer
's are comparable.
The source code of the sort method
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]);
}
}
Update
Execute this piece of code to see what happens if the class does not implements 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);
}
}
The cast to Comparable
which is done in Line 290 of ComparableTimSort.class
will fail!
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)
Upvotes: 14
Reputation: 14257
There is a big difference between type of a reference and actual type of an object it points to.
Integer i = 42;
Object o = i;
System.out.println(i.getClass());
System.out.println(o.getClass());
Output:
class java.lang.Integer
class java.lang.Integer
Both i
and o
point to an object (or value) whose runtime type is always Integer. Pointing to the object using a reference of a more general type doesn't affect its properties or behaviour in any way. This is how polymorphism works in Java.
Therefore, both of these assignments work:
Comparable<Integer> c1 = i;
Comparable<Integer> c2 = (Comparable<Integer>) o;
Upvotes: 3
Reputation: 413
Actually it is a casting problem. Initially create a integer array and then you have converted into list. I hope this one is helpful for you.
Integer[] number=new Integer[]{4,3,2,1};
Collections.sort(Arrays.asList(number));
System.out.println(Arrays.asList(number));
Upvotes: 1
Reputation: 21
Even though you are using native integer, the autobox will automatically convert it to java.lang.Integer (which implements comparable). http://docs.oracle.com/javase/8/docs/api/java/lang/Integer.html
Upvotes: 1