2017-11-23 2 views
5

Ich habe einige Artikel über statische Bindung und dynamische Bindung in Java gelesen. Und ich habe folgende Frage (Ich habe viel gesucht, aber keine Erwähnung darüber noch nicht gefunden):Probleme mit statischer Bindung und dynamischer Bindung in Java

Zum Beispiel habe ich folgende Zeilen Code:

Person a = new Student(); // Student is a subclass of Person 
a.speak(); 

Was wir schon bekannt ist, dass zur Kompilierzeit, der Compiler wird überprüft, ob es gibt Method Definition für speak() in Klasse Person und nennen Sie es, wenn es existiert. Und zur Laufzeit, wird es die speak() Methode des eigentlichen Objekts aufrufen, auf die a zeigt (Das eigentliche Objekt ist in diesem Fall eindeutig Student)

Also meine Frage ist, warum ist es nicht direkt um den Anruf speak() Methode der Klasse Studentzur Kompilierzeit, aber warten, bis Laufzeit dies zu tun? Gibt es Gründe dafür?

+0

Weil das Kompilieren Ihrer Software anders ist als das Ausführen. –

+0

Weil * Sie * dem Compiler gesagt haben, dass 'a' als' Person' und nicht als 'Student' behandelt werden soll. Und warum sollte der Code anders als von Ihnen gewünscht kompiliert werden? Welchen Vorteil ziehen Sie für diese andere Strategie an? – Holger

Antwort

3

Wenn der Code kompiliert, ist manchmal nicht klar, welche Methode aufgerufen werden muss. Sie kann nur zur Laufzeit festgelegt werden.

Nehmen Sie diesen einfachen Code als Beispiel.

class Animal{ 

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

class Dog extends Animal{ 

    //override the makeNoise() 
    public void makeNoise(){ 
     System.out.println("Woof"); 
    }; 
} 

class Cat extends Animal{ 

     //override the makeNoise() 
     public void makeNoise(){ 
      System.out.println("Meow"); 
     }; 
    } 

public class Sounds{ 

    public static void AnimalSounds(Animal animal){ 
    animal.makeNoise(); 
    } 

    public static void main(String args[]){ 

     Animal dog = new Dog();  
     Animal cat = new Cat(); 
     AnimalSounds(dog); 
     AnimalSounds(cat); 
    } 
} 

AnimalSounds(Animal animal) Methode nimmt jedes Objekt, das ISA Test of Animal und rufen das entsprechende Verfahren des Objekts übergeht. Wie Sie sehen, entfernt es auch die Code-Duplizierung, da wir dieselbe Methode für verschiedene Arten von Objekten verwenden können.

Hoffe, diese Adresse Ihr Anliegen.

+0

Danke zuerst. Aber können Sie einige Details zu "manchmal, es ist nicht klar, welche Methode aufgerufen werden muss" in Ihrem Beispiel oben angeben? – DunDev

+0

animal.makeNoise(); Zum Zeitpunkt der Kompilierung ist der Typ des Objekts nicht bekannt. Zur Laufzeit passierst du ein bestimmtes Tierobjekt und basierend darauf, ruft es die entsprechende Methode dieses Tieres auf (zB: Hund oder Katze) –

3

Um dieses Thema zu verstehen, sollten Sie wissen, was Kompilierungs- und Laufzeitprozesse im Allgemeinen sind. Kurz gesagt, wenn Sie Ihren App-Compiler erstellen, durchläuft er Ihren gesamten Code und prüft auf Konsistenz, Sicherheit und Lauffähigkeit. Wenn der Compiler keinen Fehler gefunden hat, erzeugt er class Dateien aus Ihrem Quellcode (java Dateien). Wenn die App ausgeführt wird, bedeutet dies, dass Ihre class Dateien in den Speicher geladen werden und JVM Ihre App-Anweisungen per Anweisung ausführt.

Von Ihrem Beispiel:

Person a = new Student(); // Student is a subclass of Person 
a.speak();  

Compilation Prozess: Compiler prüft diese Zeile: Person a = new Student(); für Typsicherheit (Kompatibilität). Also, wenn Student is a Person Compilation in die nächste Zeile geht, sonst scheitert es. In der nächsten Zeile: Compiler sieht a Typ, festgestellt, dass es ein Person ist und sucht nach speak() Methode bei Person Typ. Wenn diese Methode nicht vom Compiler erstellt wird, schlägt der Kompilierungsprozess fehl.

Runtime-Prozess: Wenn JVM diese Zeile ausführt: Person a = new Student(); es von oben (Elternklasse) nach unten (Kinderklasse) durch Initialisierung geht.In der nächsten Zeile: JVM Founds student Objekt durch Referenz a sucht nach Methode speak(), wenn es in Student gegründet ist führt es dann aus, andernfalls wird speak() Methode von Elternklasse Person ausgeführt.

Weitere Beispiele von Vererbung subject:

class Person { 
    public void speak() {} 
    public void think() {} 
} 

class Student extends Person { 
    @Override 
    public void speak() {} 
    public void speakALot() {} 
} 

Person a = new Student(); 
a.speak(); // calling overrided version of speak() 
a.think(); // since this method is not overrided in child class it will be called from parent class 
a.speakALot(); // since Person doesn't know anything about specific methods of derived classes compilation fails 

Student b = new Student(); 
b.speak(); // calling speak() method of student object 
b.think(); // inheritance trick, child class keeps reference to its base class and that's why public and protected fields and methods are available 
b.speakALot(); // calling speakALot() method of student object 
+0

danke, du gibst eine tolle Erklärung .. aber ich habe eine Frage, ich studiere Java von javatpoint turorials, und von diesem Link [statische Bindung und dynamische Bindung] (https://www.javatpoint.com/static-binding-and-dynamic-binding) habe ich verstanden, dass die Bindung die Operation von ist Verbinden eines Methodenaufrufs mit einem Methodenhauptteil, aber ich habe einige Probleme, einige Fälle zu verstehen, wie in Ihrem Beispiel können Sie die Antwort bearbeiten, um den Bindungstyp für jeden Methodenaufruf hinzuzufügen? oder schreib das hier. –

+1

Schauen Sie sich zuerst dieses [Tutorial] (http://javaconceptoftheday.com/static-binding-and-dynamic-binding-in-java/) an. Wenn Sie eine Frage haben, werde ich meine Antwort aktualisieren – jibrahim

+0

Ich glaube, diese Frage wird feststellen, ob ich es richtig verstanden habe oder nicht .. bedeutete das statische und dynamische Bindung Schritte (nicht Optionen), und die beiden können passieren der gleiche Methodenaufruf zur Bestimmung des Methodenkörpers muss aufgerufen werden ?? –

0

Wenn ich schreibe einfach eine Klasse für allgemeine Zwecke jede Art von Fahrzeug zu testen, wie folgt.

public class Workshop{ 
    public boolean test(Vehicle vehicle){ 
     vehicle.start(); 
     vehicle.stop(); 
     //...more code 
     return true; 
    } 
} 

ich nur mit Fahrzeugtyp diesen Code kompilieren, obwohl keines der Kinderfahrzeugklassen geschrieben wurde. Im Allgemeinen nutzen Frameworks diese Fähigkeit, eine Verarbeitung basierend auf einem generischen Typ in Abwesenheit von konkreten Typen bereitzustellen (Clients können die Kindklassenhierarchie frei erweitern). In solchen Fällen stellt der Compiler lediglich sicher, dass das Fahrzeug über mindestens eine Implementierung verfügt (null Implementierung wie {} ist ebenfalls akzeptabel), um den Code nicht zu beschädigen.