this() und Konstruktoren



  • Und auch hier nochmal 😃

    Die Java Spec 2 schreibt vor, dass zuerst alle variablen auf dem Heap angelegt werden und initialisiert und dann erst der konstruktor ausgeführt wird. Der Code ist also legal nach spec und ich würde sagen, dass der javac das verdaddelt.



  • Original erstellt von <compi>:
    Wenn ich zb schreibe Sohn s = new Sohn(); wird in den Default-Konstruktor von Sohn gesprungen. In JEDEM Konstruktor steht in der 1. Zeile implizit super() weshalb zuerst der Superklassenkonstruktor aufgerufen wird.

    Achja: Das stimmt nicht. super() steht nur in den Konstruktoren implizit, wo die erste zeile nicht shcon super( oder this( enthält. Also wird der superkonstruktor in deinem Fall NICHT vor dem this(i) aufgerufen. Trotzdem bleibt die Spec.



  • Wie ich sehe treibst du dich auch in mehreren Foren rum TriPhoenix 😉

    Was der dumme Kommentar von <Löser> sollte ist mir etwas rästelhaft...

    Allen andren danke ich für ihre Hilfe - wenngleich ich den Fehler immer noch nicht verstehe.



  • Original erstellt von <compi>:
    Wie ich sehe treibst du dich auch in mehreren Foren rum TriPhoenix 😉

    😃

    **
    Was der dumme Kommentar von <Löser> sollte ist mir etwas rästelhaft...
    **

    Vermutlich garnichts, im Assembelrforum hat er dasselbe gepostet.



  • Ich denke ich weiß jetzt warums nicht funktioniert. Instanzvariablen werden erst initialisiert (oder angelegt) _nachdem_ die Superklassenkonstruktoren aufgerufen wurden. Da in dem Defaultkonstruktor jedocht this() steht, kann der Superklassenkonstruktor nicht aufgerufen weshalb i noch nicht initialisiert ist.

    Danke an alle 🙂



  • Original erstellt von <compi>:
    **Ich denke ich weiß jetzt warums nicht funktioniert. Instanzvariablen werden erst initialisiert (oder angelegt) _nachdem_ die Superklassenkonstruktoren aufgerufen wurden. Da in dem Defaultkonstruktor jedocht this() steht, kann der Superklassenkonstruktor nicht aufgerufen weshalb i noch nicht initialisiert ist.
    **

    Dachte ich auch zuerst, aber leider nicht korrekt (zumindest wie es die Java Language Spec beschreibt). Hier mal der Auszug der dies behandelt (wichtige Sätze fett):

    ------ BEGIN QUOTE Java Language Specification 2 §12.5 ------
    Whenever a new class instance is created, memory space is allocated for it with room for all the instance variables declared in the class type and all the instance variables declared in each superclass of the class type, including all the instance variables that may be hidden (§8.3). If there is not sufficient space available to allocate memory for the object, then creation of the class instance completes abruptly with an OutOfMemoryError. Otherwise, all the instance variables in the new object, including those declared in superclasses, are initialized to their default values (§4.5.5).
    Just before a reference to the newly created object is returned as the result, the indicated constructor is processed to initialize the new object using the following procedure:

    1. Assign the arguments for the constructor to newly created parameter variables for this constructor invocation.

    2. If this constructor begins with an explicit constructor invocation of another constructor in the same class (using this), then evaluate the arguments and process that constructor invocation recursively using these same five steps. If that constructor invocation completes abruptly, then this procedure completes abruptly for the same reason; otherwise, continue with step 5.

    3. This constructor does not begin with an explicit constructor invocation of another constructor in the same class (using this). If this constructor is for a class other than Object, then this constructor will begin with an explicit or implicit invocation of a superclass constructor (using super). Evaluate the arguments and process that superclass constructor invocation recursively using these same five steps. If that constructor invocation completes abruptly, then this procedure completes abruptly for the same reason. Otherwise, continue with step 4.

    4. Execute the instance initializers and instance variable initializers for this class, assigning the values of instance variable initializers to the corresponding instance variables, in the left-to-right order in which they appear textually in the source code for the class. If execution of any of these initializers results in an exception, then no further initializers are processed and this procedure completes abruptly with that same exception. Otherwise, continue with step 5. (In some early implementations, the compiler incorrectly omitted the code to initialize a field if the field initializer expression was a constant expression whose value was equal to the default initialization value for its type.)

    5. Execute the rest of the body of this constructor. If that execution completes abruptly, then this procedure completes abruptly for the same reason. Otherwise, this procedure completes normally.
    ------ END QUOTE Java Language Specification 2 §12.5 ------

    Man sieht also, dass die Spec sagt, die Variablen VORHER initialisiert werden. Ich könnte mir aber vorstellen, dass die Sun-Compiler-Bauer fehlerhafterweise genauso gedacht haben (z.B. die Initialisierung in den Konstruktor von Object reingepackt haben) und damit die beschriebene Meldung produzieren.

    [ Dieser Beitrag wurde am 23.04.2003 um 17:14 Uhr von TriPhoenix editiert. ]



  • Das kann so nicht gehen denn die erste Zeile eines Konstruktors ist für den Aufruf eines Supertype-Konstruktors oder eines anderen Konstruktors innerhalb der selben Klasse reserviert. Ein super(); kann auch nur in der ersten Zeile des Konstruktors aufgerufen werden.

    Die Objektvariablen werden erst dann erzeugt nachdem this(i) zurückgekommen ist. Dies kann aber nicht gehen, da i noch nicht definiert ist. Deswegen die Meldung.

    Abhilfe schafft die static-Setzung von 'i' - das liegt aber wohl eher nicht im Sinn des Entwicklers.

    Andere Frage: Wie wird i überhaupt gesetzt und warum wird der Wert von i nicht via new Sohn() direkt gesetzt?

    Was ich vermute was gemacht werden soll: [java]public class Sohn {
    private static int defaultValue=0;
    private int i;

    public Sohn() {
    // Wird der parameterlose Konstruktor aufgerufen defaultValue=0
    this(defaultValue);
    }

    public Sohn(int myValue) {
    this.i = myValue;
    }
    }[/code]



  • Original erstellt von CengizS:
    **Das kann so nicht gehen denn die erste Zeile eines Konstruktors ist für den Aufruf eines Supertype-Konstruktors oder eines anderen Konstruktors innerhalb der selben Klasse reserviert. Ein super(); kann auch nur in der ersten Zeile des Konstruktors aufgerufen werden.
    **

    Genau das passiert doch, this(i) ruft einen anderen Konstruktor innerhalb der Klasse auf.

    **
    Die Objektvariablen werden erst dann erzeugt nachdem this(i) zurückgekommen ist. Dies kann aber nicht gehen, da i noch nicht definiert ist. Deswegen die Meldung.
    **

    s.o. die JLS sieht das anders 🙂



  • Da oben steht aber auch, dass das nur für den Fall gemacht wird, wenn kein Konstruktor aus der selben Klasse aufgerufen wird (per this). Und das wird in diesem Fall doch getan?



  • Original erstellt von CengizS:
    Da oben steht aber auch, dass das nur für den Fall gemacht wird, wenn kein Konstruktor aus der selben Klasse aufgerufen wird (per this). Und das wird in diesem Fall doch getan?

    Was meinst du jetzt genau? Die Initialisierung passiert ganz zu Anfang VOR JEDEM Konstruktoraufruf. (Das was ich im ersten ABsatz fett markiert habe)



  • @CengiS: Ich weiß das mein Beispiel etwas gekünstelt aussieht. Ich bin auf das Problem gestoßen als ich eine Klasse schreiben wollte, die bei der Instantiierung eines Objektes ein Array einer gewissen Größe anlegt. Wenn der Benutzer den Defaultkonstruktor aufruft sollte das Array mit einem gewissen Defaultwert initialisiert werden. Also zB so:

    public class Arr {
       private int[] value;
       private final int DEFAULT = 5;
    
       public Arr() {
          this(DEFAULT);  // Fehler
       }
    
       public Arr(int size) {
          value = new int[size];
       }
    
       ...
    }
    

    Ich bleibe bei meiner Vermutung, dass es nicht geht weil durch das this(DEFAULT) in der 1. Zeile kein implizites super() mehr eingesetzt werden kann. Da alle Instanzvariablen aber erst NACH dem Aufruf der Superklassenkonstruktoren stattfindet kann es nicht funktionieren.



  • Original erstellt von <compi>:
    Ich bleibe bei meiner Vermutung, dass es nicht geht weil durch das this(DEFAULT) in der 1. Zeile kein implizites super() mehr eingesetzt werden kann. Da alle Instanzvariablen aber erst NACH dem Aufruf der Superklassenkonstruktoren stattfindet kann es nicht funktionieren.

    Für ein solches Initialisieren stimmt es auch. Das passiert erst in Schritt 4, Während die Konstruktorenhierarchie in Schritt 3 aufgerufen wird.


Anmelden zum Antworten