2008-11-20 39 views
227

Tôi gặp sự cố khi điều hướng quy tắc của Java để suy ra các tham số loại chung. Hãy xem xét các lớp sau đây, trong đó có một số danh sách tùy chọn:Collections.emptyList() trả về một Danh sách <Object>?

import java.util.Collections; 
import java.util.List; 

public class Person { 
    private String name; 
    private List<String> nicknames; 

    public Person(String name) { 
    this(name,Collections.emptyList()); 
    } 

    public Person(String name,List<String> nicknames) { 
    this.name = name; 
    this.nicknames = nicknames; 
    } 
} 

trình biên dịch Java của tôi cung cấp cho các lỗi sau:

Person.java:9: The constructor Person(String, List<Object>) is undefined 

Nhưng Collections.emptyList() lợi nhuận gõ <T> List<T>, không List<Object>. Thêm một diễn viên không giúp

public Person(String name) { 
    this(name,(List<String>)Collections.emptyList()); 
} 

mang

Person.java:9: inconvertible types 

Sử dụng EMPTY_LIST thay vì emptyList()

public Person(String name) { 
    this(name,Collections.EMPTY_LIST); 
} 

sản lượng

Person.java:9: warning: [unchecked] unchecked conversion 

Trong khi mak thay đổi sau es lỗi sẽ biến mất:

public Person(String name) { 
    this.name = name; 
    this.nicknames = Collections.emptyList(); 
} 

Bất cứ ai có thể giải thích quy tắc kiểm tra loại nào tôi đang gặp phải ở đây và cách tốt nhất để giải quyết? Trong ví dụ này, ví dụ mã cuối cùng là thỏa đáng, nhưng với các lớp lớn hơn, tôi muốn có thể viết các phương thức sau mẫu "tham số tùy chọn" này mà không cần sao chép mã.

Để nhận thêm tín dụng: khi nào thích hợp để sử dụng EMPTY_LIST thay vì emptyList()?

+1

Đối với tất cả các câu hỏi liên quan đến Generics Java, tôi khuyên bạn nên "[Generics and Collections] Java (http://oreilly.com/catalog/9780596527754/)" của Maurice Naftalin, Philip Wadler. –

Trả lời

389

Vấn đề bạn đang gặp phải là mặc dù phương pháp emptyList() trả lại List<T>, nhưng bạn chưa cung cấp loại này, vì vậy mặc định trả lại List<Object>.Bạn có thể cung cấp thông số loại và yêu cầu mã của bạn hoạt động như mong đợi, như sau:

public Person(String name) { 
    this(name,Collections.<String>emptyList()); 
} 

Bây giờ khi bạn thực hiện thẳng, trình biên dịch có thể tìm ra các thông số kiểu chung cho bạn. Nó được gọi là suy luận kiểu. Ví dụ: nếu bạn đã thực hiện việc này:

public Person(String name) { 
    List<String> emptyList = Collections.emptyList(); 
    this(name, emptyList); 
} 

thì cuộc gọi emptyList() sẽ trả lại chính xác List<String>.

+10

OK. Đến từ thế giới ML, điều lạ lùng với tôi là Java không thể suy ra đúng loại: kiểu tham số chính thức và kiểu trả về của emptyList rõ ràng là không thể xác định được. Nhưng tôi đoán là người đánh máy chỉ có thể thực hiện "các bước em bé". –

+5

Trong một số trường hợp đơn giản, có vẻ như có thể cho trình biên dịch suy ra tham số kiểu bị thiếu trong trường hợp này - nhưng điều này có thể nguy hiểm. Nếu có nhiều phiên bản của phương thức tồn tại với các thông số khác nhau, bạn có thể sẽ gọi sai phiên bản. Và thứ hai có thể thậm chí còn chưa tồn tại ... –

+7

Ký hiệu đó "Bộ sưu tập. emptyList()" thực sự lạ, nhưng có ý nghĩa. Dễ dàng hơn Enum >. :) –

85

Bạn muốn sử dụng:

Collections.<String>emptyList(); 

Nếu bạn nhìn vào các nguồn cho những gì emptyList làm bạn thấy rằng nó thực sự chỉ làm một

return (List<T>)EMPTY_LIST; 
26

phương pháp emptyList có chữ ký này:

public static final <T> List<T> emptyList() 

Điều đó <T> trước Danh sách từ có nghĩa là nó xâm nhập giá trị của g tham số eneric T từ kiểu biến mà kết quả được gán cho. Vì vậy, trong trường hợp này:

List<String> stringList = Collections.emptyList(); 

Giá trị trả về sau đó được tham chiếu rõ ràng theo biến loại List<String>, do đó trình biên dịch có thể tìm ra. Trong trường hợp này:

setList(Collections.emptyList()); 

Không có biến trả về rõ ràng để trình biên dịch sử dụng để tìm ra loại chung, do đó mặc định là Object.

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