2012-05-16 3 views
6

gegeben ist, diese gibt 0 und 4:Java-Konstruktor ist nicht so intuitiv. Oder vielleicht ist es nicht Java, es ist C#, dass dieser Java-Code nicht intuitiv

class A{ 
    A() { print(); } 
    void print() { System.out.println("A"); } 
} 

class B extends A{ 
    int i = Math.round(3.5f); 

    public static void main(String[] args){ 
     A a = new B(); 
     a.print(); 
    } 
    void print() { System.out.println(i); } 
} 

Und mit diesem identisch C# -Code, diese gibt 4 und 4

mit System;

class A{ 
    internal A() { print(); } 
    virtual internal void print() { Console.WriteLine("A"); } 
} 

class B : A{ 
    int i = (int) Math.Round(3.5f); 

    public static void Main(string[] args){ 
     A a = new B(); 
     a.print(); 
    } 
    override internal void print() { Console.WriteLine(i); } 
} 

Obwohl ich herausfinden, dass der Ausgang 4 und 4 auf Java sein sollte, aber die Antwort ist eigentlich 0 und 4 auf Java. Dann habe ich es in C# versucht, die Antwort ist 4 und 4

Was gibt? Java rationale ist, während der Konstruktion von B, A ist immer noch initialisieren (folglich ich Posit B ist immer noch initialisiert, wenn Java sagte A ist immer noch initialisieren), so sollte der Standardwert 0 sein. Daher ist die Ausgabe 0 und 4 in Java.

Warum unterscheidet sich das C# -Konstruktorverhalten von Java oder umgekehrt?

+4

Ich lasse andere Leute das "Warum" beantworten, aber diese Art von Problemen ist der Grund, warum es allgemein als schlechte Übung angesehen wird, virtuelle Methoden von Konstruktoren aufzurufen. –

+1

+1 für den Aufruf einer virtuellen Methoden aus Konstruktor eine schlechte Praxis. Die Ausgabe ist nicht vorhersagbar angesichts unterschiedlicher Sprachen haben unterschiedliche Design-Philosophie – Hao

+0

@HovercraftFullOfEels Ich fühle das auch. Ich wollte jedoch eine Lösung finden. Wie man die Code-Absicht klarer macht oder das Code-Verhalten vorhersagbar macht, angesichts der Nuancen der Sprachen. Es mag keine klare Lösung für dieses Problem geben, aber vielleicht gibt es einige Best Practices, z.B. die virtuelle Methode sollte nicht im Konstruktor – Hao

Antwort

8

Es geschieht wegen der Unterschiede in der Reihenfolge der Objektinitialisierung in Konstruktoren.

Was geschieht in Java:

  • (leer, implizite) Konstruktor von B genannt wird
  • Superklasse Construtor von A genannt wird (prints 0, da i uninitialised ist)
  • i initialisiert nach der Oberklassenkonstruktors
  • print() aufgerufen wird (prints 4)

Was in C# passiert:

  • (leer, implizites) Konstruktor von B genannt wird
  • i vor initialisiert wird, um die Oberklassenkonstruktors
  • Superklasse Construtor von A genannt (prints 4, da ich rief genannt (prints 4)

Weder richtig oder falsch ist bereits)

  • print() initialisiert - es ist nur ein Unterschied, wie der Compiler oder ders die Bauarbeiten. Persönlich denke ich, dass die Java-Reihenfolge marginal logischer ist, weil es für mich Sinn macht, dass die Oberklasse vollständig aufgebaut ist, bevor die Unterklassen-Initialisierung stattfindet.

    Wie auch immer, weil die Logik ziemlich kompliziert werden kann, schlage ich vor, dass Sie vermeiden, während der Konstruktion von Objekten im Allgemeinen virtuelle Methoden aufzurufen.

  • +0

    Ich versuche, für das Java zu debuggen und weiß nur Schritt für Schritt, wie das Programm ausgeführt wurde, aber leider hatte ich keinen C# -Compiler. +1 für den Pseudocode. – Crazenezz

    +0

    @Crazenezz http://ideone.com – Hao

    +0

    @Hao: Schöne, aber keine Debug-Funktion :-) – Crazenezz

    1

    Die Reihenfolge der Initialisierung in Java:

    1.Die Lagerung der Instanz auf Null abgewischt wird, automatisch alle Grundelemente in dem Objekt auf die Standardwerte (Null für Zahlen und das Äquivalent für Boolesche und char Einstellung) und die Verweise auf null.

    2. Der Konstruktor der Basis class A heißt. Es wird die print Methode in class B aufrufen, da es sich um eine überschriebene Methode handelt. i ist 0 in diesem Moment.

    3. Die Member-Initialisierung der Klasse B wird ausgeführt. Also i ist jetzt 4.

    Um diese Art von Überraschung nicht zu erzeugen, rufen Sie keine nicht statischen oder nicht-privaten Methoden in einem Konstruktor auf, da sie in abgeleiteten Klassen überschrieben werden können.