Uczę się tylko języka Java i nie jestem praktykującym programistą.
Książka, którą obserwuję, mówi, że podczas nadpisywania metody typy argumentów muszą być takie same, ale typy zwracane mogą być polimorficznie kompatybilne.
Moje pytanie brzmi: dlaczego argumenty przekazane do metody zastępującej nie mogą być podklasą oczekiwanego nadtypu?
W metodzie przeciążonej każda metoda, którą wywołam na obiekcie, ma gwarancję, że zostanie zdefiniowana na obiekcie.
Uwagi na temat sugerowanych duplikatów:
Pierwsza propozycja wydaje się być o klasowej hierarchii i gdzie umieścić funkcjonalność. Moje pytanie jest bardziej skoncentrowane na tym, dlaczego istnieje ograniczenie językowe.
Druga propozycja wyjaśnia, jak zrobić to pytam, ale nie dlatego , że musi być wykonane w taki sposób. Moje pytanie dotyczy tego, dlaczego.
źródło
Odpowiedzi:
Pojęcie, do którego początkowo odwołujesz się w pytaniu, nazywa się kowariantnymi typami zwrotu .
Kowariantne typy zwracania działają, ponieważ metoda ma zwrócić obiekt określonego typu, a metody zastępujące mogą faktycznie zwrócić jego podklasę. Oparty na regułach podtypów języka takiego jak Java, jeśli
S
jest podtypemT
, to gdziekolwiek sięT
pojawi, możemy przekazaćS
.W związku z tym można bezpiecznie zwrócić wartość,
S
gdy przesłaniana jest metoda, która oczekiwała aT
.Twoja sugestia, aby zaakceptować, że przesłonięcie metody wykorzystuje argumenty, które są podtypami żądanych przez przesłoniętą metodę, jest o wiele bardziej skomplikowana, ponieważ prowadzi do nieuczciwości w systemie typów.
Z jednej strony, zgodnie z tymi samymi regułami podtytułu, o których mowa powyżej, najprawdopodobniej już działa dla tego, co chcesz zrobić. Na przykład
Nic nie stoi na przeszkodzie, aby implementacje tej klasy otrzymywały jakiekolwiek zwierzę, ponieważ spełnia ono kryteria określone w pytaniu.
Załóżmy jednak, że moglibyśmy zastąpić tę metodę, jak zasugerowałeś:
Oto zabawna część, teraz możesz to zrobić:
Zgodnie z publicznym interfejsem
AnimalHunter
powinieneś być w stanie polować na dowolne zwierzę, ale zgodnie z twoją implementacjąMammutHunter
akceptujesz tylkoMammut
przedmioty. Dlatego metoda przesłonięcia nie spełnia interfejsu publicznego. Właśnie złamaliśmy tutaj solidność systemu typów.Możesz zaimplementować to, co chcesz, używając ogólnych.
Następnie możesz zdefiniować swojego MammutHunter
Za pomocą ogólnej kowariancji i kontrawariancji możesz w razie potrzeby rozluźnić reguły na swoją korzyść. Na przykład możemy upewnić się, że łowca ssaków może polować na koty tylko w określonym kontekście:
Przypuśćmy, że
MammalHunter
narzędziaAnimalHunter<Mammal>
.W takim przypadku nie zostanie to zaakceptowane:
Nawet gdy ssaki są ssakami, nie byłoby to akceptowane z powodu ograniczeń, jakie stosujemy w tym typie przeciwstawnym. Tak więc nadal możesz ćwiczyć kontrolę nad typami, aby robić rzeczy takie jak te, o których wspomniałeś.
źródło
Problemem nie jest to, co robisz w metodzie zastępowania z obiektem podanym jako argument. Problem polega na tym, jaki jest typ argumentów, które kod używający twojej metody może przekazywać do twojej metody.
Metoda zastępująca musi spełniać warunki umowy metody zastępowanej. Jeśli przesłonięta metoda akceptuje argumenty jakiejś klasy, a przesłonisz ją za pomocą metody, która akceptuje tylko podklasę, nie spełnia ona umowy. Dlatego nie jest ważny.
Przesłonięcie metody bardziej szczegółowym rodzajem argumentu nazywa się przeciążeniem . Definiuje metodę o tej samej nazwie, ale z innym lub bardziej szczegółowym typem argumentu. Przeciążona metoda jest dostępna oprócz oryginalnej metody. Która metoda jest wywoływana, zależy od typu znanego w czasie kompilacji. Aby przeładować metodę, musisz upuścić adnotację @Override.
źródło