2010-03-10 37 views
29

Cân nhắc tôi có giao diện sau:giao diện Java và trở lại các loại

public interface A { public void b(); } 

Tuy nhiên tôi muốn mỗi người trong số các lớp học mà thực hiện nó để có một kiểu trả về khác nhau cho phương pháp b().

Ví dụ:

public class C { 
    public C b() {} 
} 

public class D { 
    public D b() {} 
} 

Làm thế nào tôi sẽ xác định giao diện của tôi vì vậy đây là có thể?

Trả lời

45

Nếu kiểu trả về phải là kiểu của lớp mà thực hiện giao diện, sau đó những gì bạn muốn được gọi là một F-bounded type:

public interface A<T extends A<T>>{ public T b(); } 

public class C implements A<C>{ 
    public C b() { ... } 
} 

public class D implements A<D>{ 
    public D b() { ... } 
} 

Nói cách, A được khai báo một tham số kiểu T mà sẽ đảm nhận giá trị của từng loại bê tông thực hiện A. Điều này thường được sử dụng để khai báo những thứ như clone() hoặc copy() các phương pháp được đánh máy tốt. Một ví dụ khác, nó được sử dụng bởi java.lang.Enum để khai báo rằng phương thức compareTo(E) được thừa kế của mỗi enum chỉ áp dụng cho các enums khác thuộc loại cụ thể đó.

Nếu bạn sử dụng mẫu này thường xuyên, bạn sẽ gặp phải các tình huống mà bạn cần this là loại T. Thoạt nhìn, có vẻ như rõ ràng là , nhưng bạn thực sự cần phải khai báo phương thức abstract T getThis() mà người triển khai sẽ phải thực hiện một cách trivially là return this.

[1] Khi người nhận xét đã chỉ ra, có thể làm điều gì đó lén lút như X implements A<Y> nếu XY hợp tác đúng cách. Sự hiện diện của phương thức T getThis() làm cho nó rõ ràng hơn khi X đang phá vỡ ý định của tác giả của giao diện A.

+0

+! - Rất đẹp. Tôi đã học được điều gì đó ở đây. Cảm ơn, Matt. – duffymo

+0

off-topic: cú pháp như thế này là lý do tại sao tôi làm hết sức mình để tránh tạo ra API tổng quát càng nhiều càng tốt. – dimitarvp

+1

Câu trả lời hay (và một ví dụ tuyệt vời về sức mạnh của generics), nhưng điều này không ngăn cản các lập trình viên làm C thực hiện A (xem câu trả lời thứ hai của tôi). – Cam

34

Generics.

public interface A<E>{ 
    public E b(); 
} 

public class C implements A<C>{ 
    public C b(){ 
     return new C(); 
    } 
} 

public class D implements A<D>{ 
    public D b(){ 
     return new D(); 
    } 
} 

Search lên Generics để biết thêm chi tiết, nhưng (rất) về cơ bản, những gì đang xảy ra là AE 's gõ lên đến clases thực hiện (CD).

Vì vậy, về cơ bản A không biết (và không cần phải biết) những gì E có thể có trong bất kỳ triển khai nhất định nào.

+3

Tôi thích cái đó nhiều hơn cái được đánh dấu là "câu trả lời", bởi vì bạn không phải dựa vào thực tế là những người triển khai thực sự sẽ bao gồm tên lớp của họ trong phần khai báo chung. Thumbs up từ tôi trên đó. – dimitarvp

+0

Tính năng này hoạt động đối với mọi loại trả lại –

2

Kể từ Java supports covariant return types (kể từ Java 1.5), bạn có thể làm:

public interface A { public Object b(); } 
+7

Không tuyệt vời. Bạn muốn giao diện của mình rời khỏi căn phòng nhỏ để lạm dụng tình cờ càng tốt. Với một phương pháp như vậy, nó sẽ rất dễ dàng cho các lập trình để thực hiện một sai lầm khi thực hiện 'A'. – Cam

+0

Câu hỏi không chỉ định rõ ràng bất kỳ hạn chế nào đối với các loại ghi đè. Tất nhiên, nếu hạn chế như vậy tồn tại, người ta nên thực thi chúng với giao diện nơi khả thi. – meriton

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