Czy metody przesłonięte mogą mieć różne typy zwracane ?
java
methods
overriding
santidoo
źródło
źródło
error: method() in subclass cannot override method() in superclass
Odpowiedzi:
Java obsługuje * kowariantne typy zwracane dla metod przesłoniętych. Oznacza to, że zastąpiona metoda może mieć bardziej szczegółowy typ zwrotu. Oznacza to, że tak długo, jak nowy zwracany typ można przypisać do zwracanego typu metody, którą zastępujesz, jest on dozwolony.
Na przykład:
class ShapeBuilder { ... public Shape build() { .... } class CircleBuilder extends ShapeBuilder{ ... @Override public Circle build() { .... }
Jest to określone w sekcji 8.4.5 specyfikacji języka Java :
(„| R2 |” odnosi się do usunięcia R2, zgodnie z definicją w §4.6 JLS .)
* Przed wersją Java 5 Java miała niezmienne typy zwracane, co oznaczało zwracany typ przesłonięcia metody niezbędny do dokładnego dopasowania zastępowanej metody.
źródło
Tak, może się różnić, ale mają pewne ograniczenia.
Przed wersją Java 5.0, gdy zastępujesz metodę, zarówno parametry, jak i zwracany typ muszą dokładnie pasować. W Javie 5.0 wprowadza nową funkcję zwaną kowariantnym typem zwrotu. Możesz przesłonić metodę z tym samym podpisem, ale zwraca podklasę zwróconego obiektu. Innymi słowy, metoda w podklasie może zwrócić obiekt, którego typ jest podklasą typu zwróconego przez metodę z tym samym podpisem w nadklasie.
źródło
Tak, jeśli zwrócą podtyp. Oto przykład:
package com.sandbox; public class Sandbox { private static class Parent { public ParentReturnType run() { return new ParentReturnType(); } } private static class ParentReturnType { } private static class Child extends Parent { @Override public ChildReturnType run() { return new ChildReturnType(); } } private static class ChildReturnType extends ParentReturnType { } }
Ten kod kompiluje się i uruchamia.
źródło
Mówiąc ogólnie tak, zwracany typ metody przesłaniania może być inny. Ale nie jest to proste, ponieważ jest kilka przypadków z tym związanych.
Przypadek 1: Jeśli typ zwracany jest pierwotnym typem danych lub void.
Dane wyjściowe: Jeśli zwracany typ jest void lub prymitywny, wówczas typ danych metody klasy nadrzędnej i metody przesłaniającej powinien być taki sam. np. jeśli zwracany typ to int, float, string, to powinien być taki sam
Przypadek 2: Jeśli zwracany typ jest pochodnym typem danych:
Dane wyjściowe: jeśli typ zwracany metody klasy nadrzędnej jest typem pochodnym, typ zwracany metody przesłaniającej jest tym samym typem danych pochodnych podklasy, co typ danych pochodnych. np. załóżmy, że mam klasę A, B jest podklasą A, C jest podklasą B, a D jest podklasą C; wtedy jeśli superklasa zwraca typ A, to metoda przesłaniająca to podklasa może zwrócić typ A, B, C lub D, tj. jego podtypy. Nazywa się to również kowariancją.
źródło
tak Jest to możliwe .. typ zwrotów może być inny tylko wtedy, gdy zwracany typ metody klasy nadrzędnej jest
super typem zwracanej metody klasy potomnej ..
oznacza
class ParentClass { public Circle() method1() { return new Cirlce(); } } class ChildClass extends ParentClass { public Square method1() { return new Square(); } } Class Circle { } class Square extends Circle { }
Jeśli tak jest, można zezwolić na inny typ zwrotu ...
źródło
Pozostałe odpowiedzi są poprawne, ale zaskakująco wszystkie pomijają tutaj aspekt teoretyczny: typy zwracanych mogą być różne, ale mogą ograniczać typ używany w superklasie ze względu na zasadę podstawienia Liskova .
To bardzo proste: gdy masz kod „klienta”, który wywołuje jakąś metodę:
int foo = someBar.bar();
wtedy powyższe musi zadziałać (i zwrócić coś, co jest
int
bez względu na to, która implementacjabar()
zostanie wywołana).Znaczenie: jeśli istnieje podklasa Bar, która nadpisuje
bar()
, nadal musisz zwrócić coś, co nie łamie „kodu dzwoniącego”.Innymi słowy: załóżmy, że baza
bar()
ma zwrócić int. Wtedy podklasa mogłaby powrócićshort
- ale nielong
dlatego, że wywołujący poradzą sobie zshort
wartością, ale nielong
!źródło
cóż, odpowiedź brzmi tak ... I NIE.
zależy od pytania. wszyscy tutaj odpowiadali na temat Java> = 5, a niektórzy wspominali, że Java <5 nie zawiera kowariantnych typów zwracanych.
w rzeczywistości specyfikacja języka Java> = 5 obsługuje tę funkcję, ale środowisko wykonawcze Java nie. w szczególności maszyna JVM nie została zaktualizowana w celu obsługi kowariantnych typów zwracanych.
co było wówczas postrzegane jako „sprytne” posunięcie, ale okazało się jedną z najgorszych decyzji projektowych w historii Javy, Java 5 zaimplementowała kilka nowych funkcji językowych bez modyfikowania JVM ani specyfikacji pliku klas. zamiast tego wszystkie funkcje zostały zaimplementowane z oszustwem w javac: kompilator generuje / wykorzystuje zwykłe klasy dla klas zagnieżdżonych / wewnętrznych, wymazywanie typów i rzutowania dla typów generycznych, syntetyczne akcesory dla prywatnej „przyjaźni” klasy zagnieżdżonej / wewnętrznej, syntetyczne pola instancji dla zewnętrznego „this” wskaźniki, syntetyczne pola statyczne dla literałów „.class” itp.
a kowariantne typy zwracane to jeszcze więcej cukru syntaktycznego dodanego przez javac.
na przykład podczas kompilowania tego:
class Base { Object get() { return null; } } class Derived extends Base { @Override @SomeAnnotation Integer get() { return null; } }
javac wyświetli dwie metody get w klasie pochodnej:
Integer Integer:Derived:get() { return null; } synthetic bridge Object Object:Derived:get() { return Integer:Derived:get(); }
wygenerowany metoda most (oznakowane
synthetic
ibridge
w kodu bajtowego) to, co faktycznie nadpisaniaObject:Base:get()
ponieważ do JVM, sposoby z różnymi rodzajami obie są całkowicie niezależne i nie mogą zastąpić siebie. aby zapewnić oczekiwane zachowanie, most po prostu wywołuje Twoją „prawdziwą” metodę. w powyższym przykładzie javac doda adnotacje zarówno do metody mostkowej, jak i rzeczywistej w Derived z @SomeAnnotation.Zwróć uwagę, że nie możesz ręcznie kodować tego rozwiązania w Javie <5, ponieważ metody mostkowe i rzeczywiste różnią się tylko typem zwracanym, a zatem nie mogą współistnieć w programie Java. ale w świecie JVM typy zwracane metod są częścią sygnatury metody (podobnie jak ich argumenty), a więc dwie metody nazwane tak samo i pobierające te same argumenty są mimo wszystko postrzegane jako całkowicie niezależne przez JVM ze względu na ich różne typy zwracania, i mogą współistnieć.
(Przy okazji, typy pól są podobnie częścią podpisu pola w kodzie bajtowym, więc dozwolone jest posiadanie kilku pól różnych typów, ale o takich samych nazwach w ramach jednej klasy kodu bajtowego.)
aby odpowiedzieć na Twoje pytanie w pełni: JVM nie obsługuje kowariantnych typów zwracanych, ale javac> = 5 udaje je w czasie kompilacji, pokrywając je ze słodkiego cukru syntaktycznego.
źródło
Przesłanianie i zwracanie typów oraz Covariant Returns
podklasa musi definiować metodę, która dokładnie pasuje do odziedziczonej wersji. Lub, od wersji Java 5, możesz zmienić zwracany typ w
przykładowy kod
Java 5, ten kod zostanie skompilowany. Jeśli miałbyś spróbować skompilować ten kod za pomocą kompilatora 1.4, powie próba użycia niezgodnego typu powrotu - sandeep1987 1 min temuclass Alpha { Alpha doStuff(char c) { return new Alpha(); } } class Beta extends Alpha { Beta doStuff(char c) { // legal override in Java 1.5 return new Beta(); } } }
źródło
Zwracany typ musi być taki sam, jak typ zwracany zadeklarowany w oryginalnej nadpisanej metodzie w nadklasie lub być jego podtypem.
źródło
TAK, to możliwe
class base { base show(){ System.out.println("base class"); return new base(); } } class sub extends base{ sub show(){ System.out.println("sub class"); return new sub(); } } class inheritance{ public static void main(String []args) { sub obj=new sub(); obj.show(); } }
źródło
Tak. Możliwe jest, że zastąpione metody mają inny typ zwracania.
Jednak ograniczenia polegają na tym, że zastąpiona metoda musi mieć typ zwracany, który jest bardziej konkretnym typem zwracanego typu rzeczywistej metody.
Wszystkie odpowiedzi podały przykłady zastąpionej metody, która ma typ zwracany, który jest podklasą typu zwracanego rzeczywistej metody.
Na przykład :
public class Foo{ //method which returns Foo Foo getFoo(){ //your code } } public class subFoo extends Foo{ //Overridden method which returns subclass of Foo @Override subFoo getFoo(){ //your code } }
Ale nie ogranicza się to tylko do podklasy, nawet klasy, które implementują interfejs, są specyficznym typem interfejsu i dlatego mogą być typem zwracanym tam, gdzie interfejs jest oczekiwany.
Na przykład :
public interface Foo{ //method which returns Foo Foo getFoo(); } public class Fizz implements Foo{ //Overridden method which returns Fizz(as it implements Foo) @Override Fizz getFoo(){ //your code } }
źródło
class Phone { public Phone getMsg() { System.out.println("phone..."); return new Phone(); } } class Samsung extends Phone{ @Override public Samsung getMsg() { System.out.println("samsung..."); return new Samsung(); } public static void main(String[] args) { Phone p=new Samsung(); p.getMsg(); } }
źródło