2017-03-02 6 views
0

Betrachten Sie die folgende Basen/abgeleiteten Klassen:Aufruf der Methode von Java-Kind-Klasse nicht in übergeordneten Klasse

public class Car { 
    private int cylinders; 

    public Car(int cyl) { 
     cylinders = cyl; 
    } 

    public int getCylinders() { 
     return cylinders; 
    } 
} 

public class SportsCar extends Car { 
    private int topSpeed; 

    public SportsCar(int cyl, int top) { 
     super(cyl); 
     topSpeed = top; 
    } 

    public int getTopSpeed() { 
     return topSpeed; 
    } 
} 

Betrachten Sie nun die folgenden zwei Objekte:

SportsCar lambo = new SportsCar(8,255); 
    Car m5 = new SportsCar(10,240); 

Die folgender Methodenaufruf kompiliert:

lambo.getTopSpeed(); 

jedoch diese Methode aufrufen, bricht mit der Fehlermeldung „kann nicht Symbol finden - Methode getTopSpeed ​​()“

m5.getTopSpeed(); 

Jetzt verstehe ich, dass die getTopSpeed Methode in der Basisklasse, um existieren muss, damit es da m5 zu kompilieren ist ein Car Typ, also, wenn ich getTopSpeed in Car dann m5.getTopSpeed(); compiles nett einschließen.

Meine Fragen sind:

  1. Warum tritt der Fehler „nicht finden können, Symbol - Methode getTopSpeed ​​()“ bei der Kompilierung passieren und nicht die Zeit laufen?
  2. Warum verhindert "späte Bindung" diesen Fehler nicht?
  3. getTopSpeed Unter der Annahme, in Car umgesetzt (so es kompiliert), wenn das Programm ausgeführt wird, wird der Compiler zunächst prüfen, ob getTopSpeed in Car existiert und dann überprüft, ob es übergegangen in SportsCar ist oder tut es einfach " wissen, "dass es bereits vom Compiler überfahren wurde und direkt die Override-Methode verwendet?
+1

Ihre erste Frage [vernünftigerweise mit dem ersten Satz beantworten] (http://stackoverflow.com/a/11466790/1079354) in dieser andere Antwort auf die Frage. Die anderen Bits, ich würde ein bisschen eine Durchsicht der JLS ermuntern. – Makoto

+1

'm5' ist eine Referenzvariable vom Typ' Car', was bedeutet, dass Sie nur Methoden aufrufen können, die in 'Car' definiert sind. Wenn Sie die Methoden in 'SportsCar' verwenden möchten, müssen Sie' m5' explizit als 'SportsCar' einsetzen. – Logan

+0

Der Compiler kann die Member eines abgeleiteten Typs nicht durch eine Variable eines übergeordneten Typs "sehen". Es gibt zwei Typen, den deklarierten Typ der _variable_, mit der der Compiler arbeitet, und den Laufzeittyp des _object_, mit dem die JVM arbeitet. Sie haben erwartet, dass der Compiler die _variable_ verarbeitet, als ob sie den Laufzeittyp des _object_ sehen könnte. Es kann nicht. –

Antwort

1
  1. Java statisch Sprache eingegeben, so dass ein Variablentyp sollte zum Zeitpunkt der Kompilierung bekannt sein. Wenn ein Typ, der dem Compiler bekannt ist, keine solche Methode verfügbar macht, ist dies ein Kompilierungsfehler. Genau aus dem Grund, es nicht zur Laufzeit zu lassen.

  2. Warum sollte es? Es findet nur die Methode Körper spät, nicht Signatur. Dennoch bedeutet statische Typisierung, dass die Signatur zur Kompilierungszeit erfüllt sein muss.

  3. Zur Laufzeit versucht JVM die spezifischste Implementierung zu finden. In SportsCar, in Ihrem Fall. Wenn es von Eltern geerbt wird, aber in Kind nicht vorhanden ist, wird der Elterncode verwendet.

Wenn Sie Methode von bestimmten Kind anrufen müssen, die in Variablentyp nicht vorhanden ist - Sie können es zur Laufzeit auf Ihr eigenes Risiko für Classcast werfen kann.

+0

Oder statt Casting, wenn Sie den Kindtyp benötigen, dann deklarieren Sie einfach die Variable als Kindtyp. Casting ist Code-Geruch. –

+0

Nun, es kommt darauf an. Ja, es erhöht das Risiko der Laufzeitausnahme. Aber andererseits, wenn Sie wissen, was Sie tun - kann es in Ordnung sein. Wie wäre es zum Beispiel mit Akka/Java-Stil der Mustererkennung für Nachrichtentypen? – iTollu

+0

Es ist immer noch Code-Geruch. In der überwiegenden Mehrzahl der Fälle, in denen ich "instanceof" verwendet habe, geht es um eine Lücke in der Typanalyse. –

1

Dies liegt daran, wenn der Compiler diese sieht:

SportsCar lambo = new SportsCar(8,255); 
Car m5 = new SportsCar(10,240); 

Es weiß Lambo ein SportsCar ist, aber nur weiß m5 ein Auto ist.Wenn Sie die Höchstgeschwindigkeit für m5 erhalten wollen, müssen Sie es auf eine SportsCar werfen müssen zuerst:

((SportsCar)m5).getTopSpeed(); 

Die meisten der Zeit, die ich gesehen habe, Gießen, jedoch wird die Variable auf eine andere Variable gegossen zuerst:

SportsCar sportsM5 = (SportsCar)m5; 
sportsM5.getTopSpeed(); 

This aspect of polymorphism in Java confused me once when I was passing an object to a method.

Verwandte Themen