Khái niệm ban đầu bạn đề cập đến trong câu hỏi của bạn được gọi là các kiểu trả về covariant .
Các kiểu trả về covariant hoạt động vì một phương thức được cho là trả về một đối tượng thuộc loại nhất định và các phương thức ghi đè có thể thực sự trả về một lớp con của nó. Dựa trên các quy tắc phân nhóm của một ngôn ngữ như Java, nếu S
là một kiểu con T
, thì bất cứ nơi nào T
xuất hiện chúng ta đều có thể vượt qua S
.
Vì vậy, an toàn để trả về một S
khi ghi đè một phương thức dự kiến a T
.
Đề xuất của bạn để chấp nhận rằng một phương thức ghi đè sử dụng các đối số là các kiểu con của các phương thức được yêu cầu bởi phương thức được ghi đè phức tạp hơn nhiều vì nó dẫn đến sự không rõ ràng trong hệ thống loại.
Một mặt, bởi các quy tắc phân nhóm tương tự được đề cập ở trên, rất có thể nó đã hoạt động cho những gì bạn muốn làm. Ví dụ
interface Hunter {
public void hunt(Animal animal);
}
Không có gì ngăn cản việc triển khai của lớp này nhận được bất kỳ loại động vật nào, vì như vậy nó đã đáp ứng các tiêu chí trong câu hỏi của bạn.
Nhưng giả sử chúng ta có thể ghi đè phương thức này như bạn đề xuất:
class MammutHunter implements Hunter {
@Override
public void hunt(Mammut animal) {
}
}
Đây là phần thú vị, bây giờ bạn có thể làm điều này:
AnimalHunter hunter = new MammutHunter();
hunter.hunt(new Bear()); //Uh oh
Theo giao diện công cộng của AnimalHunter
bạn sẽ có thể săn bất kỳ động vật nào, nhưng theo việc thực hiện của MammutHunter
bạn, bạn chỉ chấp nhậnMammut
các đối tượng. Do đó phương pháp overriden không thỏa mãn giao diện chung. Chúng tôi chỉ phá vỡ sự lành mạnh của hệ thống loại ở đây.
Bạn có thể thực hiện những gì bạn muốn bằng cách sử dụng thuốc generic.
interface AnimalHunter<T extends Animal> {
void hunt(T animal);
}
Sau đó, bạn có thể xác định MammutHunter của bạn
class MammutHunter implements AnimalHunter<Mammut> {
void hunt(Mammut m){
}
}
Và sử dụng hiệp phương sai chung và chống chỉ định, bạn có thể thư giãn các quy tắc có lợi cho bạn khi cần thiết. Chẳng hạn, chúng ta có thể chắc chắn rằng một thợ săn động vật có vú chỉ có thể săn những con mèo trong một bối cảnh nhất định:
AnimalHunter<? super Feline> hunter = new MammalHunter();
hunter.hunt(new Lion());
hunter.hunt(new Puma());
Giả sử MammalHunter
thực hiệnAnimalHunter<Mammal>
.
Trong trường hợp đó, điều này sẽ không được chấp nhận:
hunter.hunt(new Mammut()):
Ngay cả khi động vật có vú là động vật có vú, nó sẽ không được chấp nhận do những hạn chế đối với loại chống chỉ định mà chúng tôi đang sử dụng ở đây. Vì vậy, bạn vẫn có thể thực hiện một số điều khiển qua các loại để làm những việc như những gì bạn đã đề cập.