2009-04-13 25 views
311

Tôi muốn có một đối tượng Class, nhưng tôi muốn để buộc bất cứ điều gì nó đại diện lớp để mở rộng lớp A và thực hiện giao diện B.Java Generics wildcarding Với Nhiều Lớp

tôi có thể làm:

Class<? extends ClassA> 

Hoặc:

Class<? extends InterfaceB> 

nhưng tôi không thể làm cả hai. Có cách nào để làm việc này không?

Trả lời

502

Thực tế, bạn có thể làm những gì bạn muốn. Nếu bạn muốn cung cấp nhiều giao diện hoặc một lớp cộng với giao diện, bạn phải có ký tự đại diện của bạn trông như thế này:

<T extends ClassA & InterfaceB> 

Xem Generics Tutorial tại sun.com, đặc biệt là phần Bounded Type Parameters, ở dưới cùng của trang . Bạn thực sự có thể liệt kê nhiều giao diện nếu muốn, sử dụng & InterfaceName cho mỗi giao diện mà bạn cần.

Điều này có thể phức tạp tùy ý. Để chứng minh, hãy xem tuyên bố JavaDoc của Collections#max, được bao bọc trên hai dòng là:

tại sao quá phức tạp? Như đã nói trong Câu hỏi thường gặp về Java Generics: To preserve binary compatibility.

Có vẻ như điều này không hiệu quả đối với việc khai báo biến, nhưng nó hoạt động khi đặt một ranh giới chung trên một lớp. Vì vậy, để làm những gì bạn muốn, bạn có thể phải nhảy qua một vài hoops. Nhưng bạn có thể làm điều đó. Bạn có thể làm một cái gì đó như thế này, đặt một ranh giới chung trên lớp học của bạn và sau đó:

class classB { } 
interface interfaceC { } 

public class MyClass<T extends classB & interfaceC> { 
    Class<T> variable; 
} 

để có được variable có những hạn chế mà bạn muốn. Để biết thêm thông tin và ví dụ, hãy xem trang 3 của Generics in Java 5.0. Lưu ý, trong <T extends B & C>, tên lớp phải đến trước và giao diện theo sau. Và tất nhiên bạn chỉ có thể liệt kê một lớp duy nhất.

+0

Nhưng tại sao tôi phải truyền đối tượng đến T khi trả lại? –

+0

@BernhardV: Bạn cần cung cấp thêm thông tin trước khi tôi có thể trả lời. Trong trường hợp nào bạn cần phải đúc? – Eddie

+79

Điều này hữu ích. Điều đáng nói đến là lớp _must_ đến trước, bạn không thể nói ''. – EricS

11

Bạn không thể thực hiện với thông số loại "ẩn danh" (ví dụ: ký tự đại diện sử dụng ?), nhưng bạn có thể thực hiện với thông số loại "có tên". Chỉ cần khai báo tham số kiểu ở phương thức hoặc cấp lớp.

import java.util.List; 
interface A{} 
interface B{} 
public class Test<E extends B & A, T extends List<E>> { 
    T t; 
} 
+0

Tại sao không cho phép ký tự đại diện? tức là tôi không thấy lý do tại sao điều này không hợp lệ: ArrayList ; Và sau đó nếu bạn kéo một phần tử ra khỏi danh sách, bạn có thể gán cho một biến loại ClassA hoặc kiểu InterfaceB – Mark

+0

Thay thế ký tự đại diện bằng một biến là một kỹ thuật tuyệt vời! Nhưng nó không phải lúc nào cũng hiệu quả. Ví dụ, Java không cho phép các biến kiểu tên trong các kiểu giá trị chú thích, trong khi nó cho phép các ký tự đại diện. – sigpwned