webentwicklung-frage-antwort-db.com.de

Können überschriebene Methoden im Rückgabetyp abweichen?

Kann überschriebene Methoden unterschiedliche Rückgabetypen haben?

108
santidoo

Java unterstützt* kovariante Rückgabetypen für überschriebene Methoden. Dies bedeutet, dass eine überschriebene Methode einen mehr spezifischen Rückgabetyp haben kann. Solange der neue Rückgabetyp dem Rückgabetyp der Methode, die Sie überschreiben, zugewiesen werden kann, ist dies zulässig.

Zum Beispiel:

class ShapeBuilder {
    ...
    public Shape build() {
    ....
}

class CircleBuilder extends ShapeBuilder{
    ...
    @Override
    public Circle build() {
    ....
}

Dies ist in Abschnitt 8.4.5 der Java-Sprachspezifikation angegeben :

Rückgabetypen können bei Methoden, die sich überschreiben, unterschiedlich sein, wenn es sich bei den Rückgabetypen um Referenztypen handelt. Der Begriff der Rückgabetyp-Ersetzbarkeit unterstützt kovariante Rückgaben, d. H. Die Spezialisierung des Rückgabetyps auf einen Subtyp.

Eine Methodendeklaration d1 mit dem Rückgabetyp R1 ist nur dann für die andere Methode d2 mit dem Rückgabetyp R2 austauschbar, wenn die folgenden Bedingungen zutreffen:

  • Wenn R1 ungültig ist, ist R2 ungültig.

  • Wenn R1 ein primitiver Typ ist, ist R2 identisch mit R1.

  • Wenn R1 ein Referenztyp ist, dann:

    • R1 ist entweder ein Subtyp von R2 oder R1 kann durch ungeprüfte Konvertierung in einen Subtyp von R2 konvertiert werden (§5.1.9) oder

    • R1 = | R2 |

("| R2 |" bezieht sich auf die Löschung von R2, wie in §4.6 der JLS definiert.)


* Vor Java 5 hatte Java invariant Rückgabetypen. Dies bedeutete, dass der Rückgabetyp einer Methodenüberschreibung erforderlich war, um genau mit der überschriebenen Methode übereinzustimmen.

149

Ja, es kann abweichen, aber es gibt einige Einschränkungen.

Wenn Sie vor Java 5.0 eine Methode überschreiben, müssen beide Parameter und der Rückgabetyp genau übereinstimmen. In Java 5.0 wird eine neue Funktion namens kovarianter Rückgabetyp eingeführt. Sie können eine Methode mit derselben Signatur überschreiben, gibt jedoch eine Unterklasse des zurückgegebenen Objekts zurück. Mit anderen Worten, eine Methode in einer Unterklasse kann ein Objekt zurückgeben, dessen Typ eine Unterklasse des Typs ist, der von der Methode mit der gleichen Signatur in der Oberklasse zurückgegeben wird.

19
Pankaj Goyal

Ja, wenn sie einen Subtyp zurückgeben. Hier ist ein Beispiel:

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 {
    }
}

Dieser Code wird kompiliert und ausgeführt.

18
Daniel Kaplan

Im großen und ganzen kann die Methode der Rückgabe von Überschreibungsmethoden unterschiedlich sein. Aber es ist nicht klar, dass einige Fälle damit einhergehen.

Fall 1: Wenn der Rückgabetyp primitiver Datentyp oder ungültig ist.

Ausgabe: Wenn der Rückgabetyp ungültig oder primitiv ist, sollte der Datentyp der übergeordneten Klassenmethode und der überschreibenden Methode derselbe sein. Wenn der Rückgabetyp int, float, string ist, sollte er gleich sein

Fall 2: Wenn der Rückgabetyp der abgeleitete Datentyp ist:

Ausgabe: Wenn der Rückgabetyp der übergeordneten Klassenmethode ein abgeleiteter Typ ist, ist der Rückgabetyp der überschreibenden Methode der gleiche abgeleitete Datentyp der Unterklasse wie der abgeleitete Datentyp . Angenommen, ich habe eine Klasse A B ist Unterklasse für A C ist Unterklasse zu B D ist Unterklasse zu C Wenn die Superklasse dann Typ A zurückgibt, kann die überschreibende Methode die Unterklasse A, B, C oder D, d. h. ihre Untertypen, zurückgeben. Dies wird auch als Covarience bezeichnet.

6
Avinav Mishra

ja Es ist möglich. Der Rückgabetyp kann nur anders sein, wenn der Rückgabetyp der übergeordneten Klassenmethode ist
Ein Supertyp des Rückgabetyps der untergeordneten Klassenmethode ..
meint 

            class ParentClass {
                  public Circle() method1() {
                    return new Cirlce();
                  }
            }

            class ChildClass extends ParentClass {
                  public Square method1() {
                     return new Square();
               }
            }


            Class Cirlce {

            }

            class Square extends Circle {

            }

        ---

Wenn dies der Fall ist, kann ein anderer Rückgabetyp zugelassen werden ...

Überschreibungs- und Rückgabetypen und kovariante Rückgaben  
Die Unterklasse muss eine Methode definieren, die der geerbten Version genau entspricht. Oder Sie können ab Java 5 den Rückgabetyp in ändern 

beispielcode


                                                                                                            class 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();
                    }
             } } 
Ab Java 5 wird dieser Code kompiliert. Wenn Sie versuchen würden, diesen Code mit einem 1.4-Compiler zu kompilieren, wird versucht, den inkompatiblen Rückgabetyp Sandeep1987 vor 1 Minute zu verwenden

2
sandeep1987

Der Rückgabetyp muss mit dem deklarierten Rückgabetyp identisch sein oder ein Subtyp davon sein. __ in der ursprünglich überschriebenen Methode in der Superklasse.

2
sandeep1987

Die anderen Antworten sind alle richtig, lassen aber überraschenderweise den theoretischen Aspekt außer Acht: Rückgabetypen können unterschiedlich sein, aber sie können nur den Typ einschränken , der in verwendet wird die Superklasse wegen des Liskov Substitution Principle .

Es ist ganz einfach: Wenn Sie "Client" -Code haben, der eine Methode aufruft:

int foo = someBar.bar();

dann muss das obige funktionieren (und etwas zurückgeben, das ein int ist, unabhängig davon, welche Implementierung von bar() aufgerufen wird).

Das heißt: Wenn es eine Bar-Unterklasse gibt, die bar() überschreibt, müssen Sie immer noch etwas zurückgeben, das den "Anrufercode" nicht verletzt.

Mit anderen Worten: Nehmen Sie an, dass die Basis bar() int zurückgeben soll. Dann könnte eine Unterklasse short zurückgeben - aber nicht long, da Aufrufer gut mit einem short Wert umgehen können, aber nicht mit einem long!

1
GhostCat

JA kann es möglich sein 

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();
 }
}
1
Rahul Bhadana

nun, die Antwort ist ja ... und nein.

kommt auf die frage an. Alle hier beantworteten Fragen zu Java> = 5, und einige erwähnten, dass Java <5 keine kovarianten Rückgabetypen enthält.

tatsächlich wird es von der Java-Sprachspezifikation> = 5 unterstützt, die Java-Laufzeit jedoch nicht. Insbesondere wurde die JVM nicht aktualisiert, um kovariante Rückgabetypen zu unterstützen.

java 5 implementierte eine Reihe neuer Sprachfunktionen, ohne die JVM- oder Klassendateispezifikationen zu ändern. Dies galt damals als "kluger" Schachzug, stellte jedoch eine der schlimmsten Entwurfsentscheidungen in der Geschichte von Java dar. Stattdessen wurden alle Funktionen mit Trick in Javac implementiert: Der Compiler generiert/verwendet einfache Klassen für verschachtelte/innere Klassen, Type Erasure und Casts für Generics, synthetische Accessoren für verschachtelte/innere Klassen, private "Friendship", synthetische Instanzfelder für äußere "this". Zeiger, synthetische statische Felder für Literale der Klasse usw. usw.

und kovariante Rückgabetypen sind noch syntaktischer Zucker, der von Javac hinzugefügt wird.

zum Beispiel beim Kompilieren von:

class Base {
  Object get() { return null; }
}

class Derived extends Base {
  @Override
  @SomeAnnotation
  Integer get() { return null; }
}

javac gibt zwei get-Methoden in der Derived-Klasse aus:

Integer Integer:Derived:get() { return null; }
synthetic bridge Object Object:Derived:get() { return Integer:Derived:get(); }

die generierte Bridge-Methode (markiert mit synthetic und bridge im Bytecode) setzt Object:Base:get() tatsächlich außer Kraft, da für die JVM Methoden mit unterschiedlichen Rückgabetypen völlig unabhängig sind und sich nicht überschreiben können. Um das erwartete Verhalten bereitzustellen, ruft die Bridge einfach Ihre "echte" Methode auf. Im obigen Beispiel kommentiert javac sowohl Bridge- als auch Real-Methoden in Derived with @SomeAnnotation.

beachten Sie, dass Sie diese Lösung nicht in Java <5 handcodieren können, da Bridge- und Real-Methoden sich nur im Rückgabetyp unterscheiden und daher in einem Java-Programm nicht koexistieren können. In der JVM-Welt sind Methodenrückgabetypen jedoch Teil der Methodensignatur (genau wie ihre Argumente), sodass die beiden Methoden mit demselben Namen und denselben Argumenten aufgrund ihrer unterschiedlichen Rückgabetypen von der JVM als vollständig unabhängig angesehen werden. und koexistieren können.

(Übrigens sind die Feldtypen in Bytecode ebenfalls Teil der Feldsignatur, daher ist es zulässig, dass mehrere Felder unterschiedlichen Typs in einer einzelnen Bytecode-Klasse den gleichen Namen haben.)

um Ihre Frage vollständig zu beantworten: Die JVM unterstützt keine kovarianten Rückgabetypen, aber javac> = 5 fälscht sie beim Kompilieren mit einem Überzug aus süßem syntaktischem Zucker.

0
Lanchon

Ja. Überschriebene Methoden haben möglicherweise einen anderen Rückgabetyp.

Die Einschränkungen bestehen jedoch darin, dass die überschriebene Methode einen Rückgabetyp haben muss, der spezifischer für den Rückgabetyp der tatsächlichen Methode ist.

Alle Antworten haben Beispiele für die überschriebene Methode gegeben, um einen Rückgabetyp zu erhalten, der eine Unterklasse des Rückgabetyps der tatsächlichen Methode ist.

Zum Beispiel :

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         
  }

}

Dies ist jedoch nicht nur auf die Unterklasse beschränkt. Selbst Klassen, die eine Schnittstelle implementieren, sind ein bestimmter Typ der Schnittstelle und können daher ein Rückgabetyp sein, bei dem die Schnittstelle erwartet wird.

Zum Beispiel :

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         
  }

}
0
Sachin Kumar

Ja können wir haben! Der kovariante Rückgabetyp ist eines der häufigsten Beispiele

0
user11198642