2010-02-10 29 views
5

Tôi đã gặp một số mã ngày hôm nay mà tôi thấy có vấn đề. Đây là một ví dụ đơn giản (không thực tế).Sử dụng Generics Java trong giao diện trả về bộ sưu tập. Thực hành tốt nhất? Cạm bẫy?

public interface IListable { 
    //returns first n items from list 
    public ArrayList getFirstNThings(int n); 

    //returns last n items from list 
    public ArrayList getLastNThings(int n); 
} 

Sau đó có một implementor như vậy:

public GroceryList implements IListable { 
    private ArrayList<GroceryItem> groceries; 

    public GroceryList() { 
     this.groceries = new ArrayList<GroceryItem>(); 
    } 

    public ArrayList<GroceryItem> getFirstNThings(int n) { 
     ArrayList<GroceryItem> firstNThings = new ArrayList<GroceryItem>(); 
     for (int i=0; i < n; i++) { 
      firstNThings.add(this.groceries.get(i)); 
     } 
     return firstNThings 
    } 

    public ArrayList<GroceryItem> getLastNThings(int n) { 
     ArrayList<GroceryItem> lastNThings = new ArrayList<GroceryItem>(); 
     for (int i=this.groceries.size(); i < this.groceries.size()-n; i--) { 
      lastNThings.add(this.groceries.get(i-1); 
     } 
     return lastNThings; 
     } 
} 

Bỏ qua bất kỳ vấn đề thực hiện bạn có thể tìm thấy trong đó (tôi tìm thấy một vài quá). Điều tôi nhận được ở đây là giao diện không sử dụng bất kỳ tham số kiểu generic nào cho ArrayList (ví dụ ArrayList <?>), Nhưng trình triển khai phương thức của giao diện (ví dụ: ArrayList < GroceryList>). Những người triển khai khác có thể trả về ArrayLists với bất kỳ tham số kiểu nào khác, không?

Vì vậy, câu hỏi của tôi: Đây có phải là sự cố không? Tôi có nên refactor bất cứ điều gì? Nó có đáng không? Lợi thế là gì? Tôi có thể chạy loại vấn đề nào nếu tôi có một phương thức được xác định trong giao diện có kiểu trả về là kiểu thô, nhưng những người triển khai thực tế của phương thức trả về các kiểu tham số khác nhau?

+2

Bên cạnh những gì sfussenegger đã nói, tôi cũng muốn các phương thức trả về 'Danh sách' thay vì' ArrayList'. –

Trả lời

5

nếu cả hai phương pháp IListable luôn luôn trở về cùng loại, sử dụng này để thay thế:

public interface IListable<T> { 
    //returns first n items from list 
    public ArrayList<T> getFirstNThings(int n); 

    //returns last n items from list 
    public ArrayList<T> getLastNThings(int n); 
} 

nếu đây không phải là một lựa chọn, hãy thử sử dụng? thay thế. Mặc dù về cơ bản giống nhau, nó tránh cảnh báo xấu.

public interface IListable { 
    //returns first n items from list 
    public ArrayList<?> getFirstNThings(int n); 

    //returns last n items from list 
    public ArrayList<?> getLastNThings(int n); 
} 

Nói chung, không phải là vấn đề khi sử dụng loại trả lại cụ thể hơn trong triển khai hơn là siêu loại hoặc giao diện. Nếu bạn đang đối phó với IListable, bạn cần phải xử lý bất kỳ loại đối tượng trong danh sách trả về. Nếu bạn đang giao dịch với GroceryList, bạn chỉ mong đợi GroceryItems. Điều đó không chỉ đúng với các đối số kiểu gen của các kiểu trả về, mà còn đối với kiểu trả về chính nó. Vì vậy, nếu một giao diện chỉ định List<Foo> get(), bạn có thể triển khai giao diện đó dưới dạng ArrayList<Foo> get().

+0

Phương pháp này cũng cho phép bạn biến GroceryList thành danh sách được nhập hoàn toàn chung để sử dụng lại sau này. – Thirler

0

Thực hành tốt nhất là không bao giờ quay trở lại một List<?> với tinh khiết ký tự đại diện trong mở mã của bạn, giống như bạn không phải trả lại null.

Generics wildcard trong Java sẽ mang lại sự ô nhiễm cho tất cả các lập trình viên sử dụng mã của bạn. Bạn có thể làm điều đó trong mã số Đóng để giải quyết sự cố địa phương.

Thông thường, bạn sẽ tránh được trở về hiệp phương sai và contravariance ký tự đại diện như List<? extends User>List<? super User>

Bạn có thể làm điều đó nếu bạn biết những gì bạn đang làm và đọc mọi thứ về PECS, và bounded wildcards. Đừng làm điều đó chỉ vì nó biên dịch.

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