Können wir in Java Superklassenobjekt an Unterklassenreferenz übergeben?

8

Können wir in Java das Überklassen-Objekt an die Unterklassenreferenz übergeben?

Ich weiß, dass es eine komische Frage ist / praktisch nicht lebensfähig, aber ich möchte die Logik dahinter verstehen Warum ist es in Java nicht erlaubt?

%Vor%

Was wäre passiert, wenn Java die Kompilierung von Zeile 1 erlaubt hätte? Wo würde das Problem entstehen?

Alle Eingaben / Links sind willkommen.

    
Rajul Konkar 24.06.2014, 10:42
quelle

3 Antworten

18

Wenn Ihre SalesPerson sales = new Employee(); -Anweisung kompilieren durfte, hätte dies die Prinzipien von Polymorphismus verletzt , was eines der Merkmale der Sprache ist.

Sie sollten sich auch damit vertraut machen, dass Kompilierzeittyp und Laufzeittyp bedeuten:

Der Kompilierzeittyp einer Variablen ist der Typ, für den er deklariert ist, während der Laufzeittyp der Typ des tatsächlichen Objekts ist, auf das die Variable zeigt. Zum Beispiel:

%Vor%

Der Kompilierungszeittyp von sales ist Employee und der Laufzeittyp ist SalesPerson . Der Kompilierzeittyp definiert, welche Methoden aufgerufen werden können, während der Laufzeittyp definiert, was während des tatsächlichen Aufrufs geschieht.

Nehmen wir einmal an, diese Aussage sei gültig:

%Vor%

Wie gesagt, der Typ der Kompilierzeit definiert, welche Methoden aufgerufen werden können, also wäre met2() für den Aufruf geeignet gewesen. In der Zwischenzeit hat die Employee -Klasse kein met2() und somit wäre der eigentliche Aufruf unmöglich gewesen.

    
Konstantin Yovkov 24.06.2014, 10:48
quelle
4

Nein. Es macht keinen Sinn, das zuzulassen.

Der Grund dafür ist, dass Unterklassen im Allgemeinen zusätzliches Verhalten definieren. Wenn Sie einer Unterklassenreferenz ein Objekt der Superklasse zuweisen könnten, würden Sie zur Laufzeit auf Probleme stoßen, wenn Sie versuchen, auf Klassenmitglieder zuzugreifen, die nicht wirklich existieren .

Zum Beispiel, wenn dies erlaubt wäre:

%Vor%

Sie würden einige ziemlich schlechte Probleme bekommen. Was passiert, wenn Sie versuchen, eine String -Methode aufzurufen? Würde die Laufzeit abstürzen? Oder vielleicht würde ein No-Op durchgeführt werden? Soll das überhaupt kompiliert werden?

Wenn die Laufzeit abstürzen würde, könnten Sie Laufzeitprüfungen verwenden, um sicherzustellen, dass die Objekte, die Sie erhalten, tatsächlich die gewünschten Methoden enthalten. Aber dann implementiert man im Grunde Garantien, dass das Java-Typsystem zur Kompilierzeit bereits bereitstellt . Also kostet dieses "Feature" wirklich nichts als einen Haufen Code-Checking-Code, den Sie eigentlich gar nicht hätten schreiben müssen.

Wenn keine Ops anstelle von nicht existierenden Methoden ausgeführt wurden, wäre es extrem schwierig sicherzustellen, dass Ihre Programme wie geschrieben ausgeführt würden, wenn die Mitglieder, auf die Sie zugreifen wollen, nicht existieren, da jede Referenz wirklich ein Object sein könnte. an jedem Punkt. Dies kann leicht zu handhaben sein, wenn Sie alleine arbeiten und Ihren gesamten Code kontrollieren, aber wenn Sie mit anderem Code umgehen müssen, verschwinden diese Garantien im Wesentlichen.

Wenn Sie möchten, dass der Compiler die Überprüfung durchführt, vorausgesetzt, dass Compiler-Autoren Sie nicht im Stich lassen und Ihnen ein ernstes Gespräch geben, dann sind Sie wieder bei "normalem" Verhalten. Also wieder, es ist nur eine Menge Arbeit für null Nutzen.

Lange Rede, kurzer Sinn: Nein, das ist nicht erlaubt, weil es keinen Sinn macht, das zu tun, und wenn ein Sprachgestalter versuchen würde zuzulassen, dass sie eingesperrt werden, bevor sie noch mehr Schaden anrichten können.

    
awksp 24.06.2014 10:56
quelle
3

Wenn Sie von einer Klasse erben, spezialisieren Sie immer das allgemeine Verhalten der Superklasse.

In Ihrem Beispiel ist SalesPerson eine spezielle Employee . Es übernimmt das gesamte Verhalten der Superklasse und kann das Verhalten überschreiben, um es anders zu machen oder neues Verhalten hinzuzufügen.

Wenn Sie, wie es erlaubt ist, eine Variable vom Super-Typ mit einer Instanz des Subtyps wie Employee e = new SalesPerson() initialisieren, können Sie alle üblichen Verhaltensweisen für diese Variable verwenden.

Wenn Sie stattdessen umgekehrt vorgehen könnten, könnte es mehrere nicht initialisierte Mitglieder in der Klasse geben.

Sie finden dies sehr oft bei der Verwendung der Java Collection API, wo Sie beispielsweise die allgemeine List -Klasse für Operationen wie Iterieren verwenden können, aber bei der Initialisierung verwenden Sie beispielsweise die Unterklasse ArrayList .

    
Alexander Rühl 24.06.2014 10:53
quelle