2015-09-04 20 views
17

Bạn có thể giải thích tại sao mã sau đây biên dịch và in [1, 2, 3, 4], như mong đợi. Tôi đang sử dụng Java 8.Tại sao mã sau sắp xếp Danh sách đối tượng?

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

Như tôi đã hiểu, bốn trường hợp Integer được tạo tại đây. Mỗi mục danh sách chứa một tham chiếu đối tượng đến một thể hiện Integer. Vì lớp Object không thực hiện giao diện Comparable, nên Collections.sort sẽ ném ClassCastException hoặc một cái gì đó như thế này bởi vì nó không thể truyền các tham chiếu Object tới các tham chiếu Comparable.

Bạn có thể chỉ ra những gì tôi đang thiếu không?

+2

Vì bạn đang sử dụng Java 8, vui lòng sử dụng * generics *: 'List nums', cũng trả lời câu hỏi của bạn. – Andreas

+1

Bạn không thể có một Bộ sưu tập nguyên thủy trong Java, vì vậy chúng được tự động đóng vào loại tương đương của chúng. 'int' được tự động đóng hộp thành' Integer' mà DOES thực hiện so sánh. – McNultyyy

+0

Cuối cùng, chúng chỉ là đối tượng khi được thêm vào danh sách. Các đối tượng lớp nguyên là chúng. Lớp Integer thực hiện giao diện tương đương. Vì vậy, cuối cùng của nó Integer, không chỉ Object – SacJn

Trả lời

14

Với 1,2,3,4 bạn đang tạo int literals. Trong khi chuyển chúng đến asList(T... a) chúng được đóng hộp thành Integer các đối tượng triển khai Comparable (public final class Integer extends Number implements Comparable<Integer>), để bạn có thể sắp xếp chúng.

Cập nhật

Bình luận: Có, nhưng danh sách được khai báo là Danh sách, vì vậy nó là từ đồng nghĩa với List<Object>, không List<Integer>, và Object không thực hiện Comparable.

Trả lời: Bạn không chỉ định loại chung cho danh sách và phương pháp Collections.sort() chỉ kiểm tra xem lớp của đối tượng có mở rộng Comparable hay không. Nếu danh sách không có loại, trình biên dịch của bạn chỉ nên cung cấp cho bạn một cảnh báo và mọi thứ sẽ hoạt động tốt vì Integer có thể so sánh được.

Mã nguồn của cách sắp xếp

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]); 
    } 
} 

Cập nhật

Execute đoạn mã này để xem những gì sẽ xảy ra nếu lớp không thực hiện 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); 
    } 
} 

Dàn diễn viên để Comparable đó được thực hiện trong dòng 290 của ComparableTimSort.class sẽ thất bại!

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) 
+0

Có, nhưng Danh sách được khai báo là Danh sách, do đó, nó là từ đồng nghĩa với Danh sách , không phải Danh sách và Object không triển khai Có thể so sánh. – savak

+3

@savak 'Danh sách' không phải là một từ đồng nghĩa cho' Danh sách '. 'List' về cơ bản sẽ tắt tất cả các tính năng chung. Nó dành cho mã được viết trước khi generics tồn tại. Kiểm tra rằng T mở rộng Comparable là một trong những kiểm tra không xảy ra khi bạn không sử dụng Generics. – immibis

+0

Cảm ơn rất nhiều. Tôi chắc chắn nghĩ rằng Danh sách và Danh sách là cùng một tuyên bố. – savak

1

Mặc dù bạn đang sử dụng số nguyên gốc, hộp tự động sẽ tự động chuyển đổi nó thành java.lang.Integer (có thể so sánh được). http://docs.oracle.com/javase/8/docs/api/java/lang/Integer.html

+0

Có, nhưng Danh sách được khai báo là Danh sách, do đó, nó là từ đồng nghĩa với Danh sách , không phải Danh sách và Object không triển khai Có thể so sánh. – savak

1

Thực ra đó là sự cố truyền. Ban đầu tạo một mảng nguyên và sau đó bạn đã chuyển đổi thành danh sách. Tôi hy vọng điều này là hữu ích cho bạn.

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

Có sự khác biệt lớn giữa loại tham chiếu và loại thực tế của đối tượng mà đối tượng trỏ đến.

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 

Cả io điểm đến một đối tượng (hoặc giá trị) có loại thời gian chạy luôn là Integer.Việc trỏ đến đối tượng bằng cách sử dụng tham chiếu của một loại tổng quát hơn không ảnh hưởng đến thuộc tính hoặc hành vi của nó theo bất kỳ cách nào. Đây là cách đa hình hoạt động trong Java.

Do đó, cả hai bài tập làm việc:

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

Các mảnh còn thiếu ở đây là loại tẩy xoá.

Biên dịch Java sang mã bytecode JVM và bytecode JVM không có khái niệm về generics. Vì vậy, trong thời gian chạy, List chính xác giống như List<Comparable> hoặc List<Object>. Nếu mã của bạn đã từng chứa thông tin đó (mã của bạn không), thì mã đó sẽ bị xóa khi mã của bạn được biên dịch.

Điều này có nghĩa rằng khi chạy, không có sự khác biệt giữa một List<Object>List<Comparable>, trừ các yếu tố thực tế chúng chứa (do đó, nó cũng có nghĩa là nếu List của bạn không chứa yếu tố, sau đó không có cách nào nói với những gì loại List nó có nghĩa là phải).

Collections.sort có thể sắp xếp bất kỳ List mà các thành phần của chúng đều thực hiện Comparable và có thể so sánh được với nhau. Vì số List của bạn chứa Integer s, thực hiện Comparable, Collections.sort có thể sắp xếp.

Có thể gây nhầm lẫn, điều này không đúng với các mảng vì lý do lịch sử. Comparable[]Object[] là các loại hoàn toàn khác nhau. Về nguyên tắc, điều này có nghĩa là các phương thức phân loại mảng của Java có thể từ chối phân loại các mảng Object[], như bạn có thể mong đợi. Trong thực tế họ không, và Arrays.sort chấp nhận Object[] mảng, tương tự như Collections.sort.

Các vấn đề liên quan