2014-06-24 5 views
8

In Java, können wir Superklasse Object zu Unterklassenreferenz übergeben?Können wir in Java Superklassenobjekt zu Unterklassenreferenz übergeben?

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

class Employee { 
    public void met1(){ 
     System.out.println("met1"); 
    } 
} 


class SalesPerson extends Employee 
{ 
    @Override 
    public void met1(){ 
    System.out.println("new met1"); 
    } 


    public void met2(){ 
     System.out.println("met2"); 
    } 

} 

public class ReferenceTest { 
    public static void main(String[] args) { 

     SalesPerson sales = new Employee(); // line 1 

     sales.met1(); // line 2 

     sales.met2(); // line 3 
    } 
} 

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

Alle Eingänge/Links sind willkommen.

+1

Es würde keinen Sinn ergeben. Wenn es erlaubt wäre, könnten Sie Felder/Methoden haben, die Sie erwarten würden, dort zu sein, die nicht wirklich dort sind. Wenn es erlaubt wäre, wären die Sprachdesigner vielleicht irgendwo weggeschlossen worden, wo sie keinen Schaden mehr anrichten könnten. – awksp

+0

was erwartest du würde passieren? – Mark

Antwort

18

Wenn Ihre SalesPerson sales = new Employee(); Anweisung kompilieren durfte, hätte dies die Prinzipien Polymorphism verletzt, die eine der Funktionen der Sprache ist.

Außerdem sollten Sie mit dem vertraut macht Kompilierung Typ und Laufzeittyp Mittelwert:

Die Kompilierung-Typ einer Variablen ist der Typ als, während der erklärt Der Laufzeittyp ist der Typ des tatsächlichen Objekts, auf das die Variable verweist. Zum Beispiel:

Employee sales = new SalesPerson(); 

Der Kompilierung-Typ von sales ist Employee und der Laufzeittyp SalesPerson sein wird. Der Kompilierzeittyp definiert, welche Methoden aufgerufen werden können, während der Laufzeittyp definiert, was während des aktuellen Aufrufs geschieht.

für einen Moment Nehmen wir an, dass diese Aussage gültig war:

SalesPerson sales = new Employee(); 

Wie gesagt, die Kompilierung-Typ legt fest, welche Methoden aufgerufen werden können, so würde met2() für den Aufruf berechtigt gewesen sein. Unterdessen hat die Employee Klasse keine met2() und so wäre der eigentliche Anruf unmöglich gewesen.

+0

Perfekte Antwort. – user2601010

+0

Wie wäre es mit Mitarbeiter e = new SalesPerson(); e.met2(); Ich denke, es ist möglich, aber wie? Die Kompilierzeit hat keine Methode met2(). Sollte es keinen Fehler werfen? – RajSharma

+0

@RajSharma nicht erlaubt. Es wird einen Fehler bei der Kompilierung geben, da es in Employee keine Methode met2() gibt – crazyStart

3

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

In Ihrem Beispiel ist die 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 eine Variable des Supertyps mit einer Instanz des Subtyps wie Employee e = new SalesPerson() initialisieren können, dann können Sie alle gemeinsamen 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 dies sehr oft finden, wenn die Java-Sammlung API verwenden, wo Sie zum Beispiel die gemeinsame List Klasse auf Operationen wie Iterieren durch sie verwenden können, aber wenn es zu initialisieren, verwenden Sie beispielsweise für die Unterklasse ArrayList.

4

Nein. Es macht keinen Sinn, das zuzulassen.

Der Grund ist, weil Unterklassen allgemein zusätzliche Verhalten definieren. Wenn Sie einer Unterklassenreferenz ein Objekt der Oberklasse zuweisen könnten, würden Sie zur Laufzeit auf Probleme stoßen, wenn Sie versuchen, auf Klassenmitglieder zuzugreifen, die tatsächlich nicht existieren.

Zum Beispiel, wenn dies erlaubt wurde:

String s = new Object(); 

Sie würden in ein paar ziemlich schlechte Probleme stoßen. 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 kompilieren?

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 implementieren Sie im Grunde Garantien, die das Java-Typsystem bereits zur Kompilierungszeit bereitstellt. Also kostet dieses "Feature" wirklich nichts als eine Menge Code-Check-Code, den Sie eigentlich gar nicht hätten schreiben müssen.

Wenn keine Ops anstelle von nicht vorhandenen 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 möchten, nicht existieren, da jede Referenz eine Object sein könnte irgendein 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, es ist nicht erlaubt, weil es null Sinn, so zu tun macht, und wenn eine Sprache Designer versucht, zu ermöglichen, dass sie eingesperrt werden würden, bevor sie mehr Schaden anrichten könnten.

Verwandte Themen