Konstruktor-Aufruf im Konstruktor, aber nicht am Anfang?

Michael B.

Neues Mitglied
Hallo zusammen,
ich habe noch nicht viel in Java programmiert, und bin jetzt auf ein kleines Problem gestoßen. Ich will einen Konstruktor in einem anderen aufrufen, ungefähr so:

Java:
public class myclass {
    String s1, s2;
    
    myclass (String t1, String t2) {
        s1 = t1;
        s2 = t2;
        // weiterer Code
    }
    
    myclass (String t) {
        String t2;
        String[] split=t.split(",");
    
        if (split.length < 2) t2 = "defaultstring";
            else t2 = split[1];
        
        this (split[0], t2); // geht nicht!
    }
}

Das klappt nicht, weil der Aufruf des Konstruktors mit "this" am Anfang stehen muss. Ich kann ihn aber nicht an den Anfang setzen, weil ja zuerst die Zeichenkette aufgespalten werden muss.

Auch würde ich die Elemente s1 und s2 ungern direkt im zweiten Konstruktor setzen, weil im ersten in Wirklichkeit noch ein paar Berechnungen gemacht und static-Variablen gesetzt werden.

Vielleicht könnte man auch alles in eine Zeile schreiben, ungefähr so:
Java:
myclass (String t) {
    this (t.split(","))[0], ((t.split).length<2) ? "defaultstring" : (t.split(","))[1]);
}
Ich hab's nicht ausprobiert. Aber leider werden auch im zweiten Konstruktor mit den aufgespaltenen Strings noch diverse Sachen gemacht, die ich so einfach nicht in einer Zeile unterbringe.

Vermutlich muss man das ganz anders anfangen. Aber wie am besten?

Vielen Dank schon mal
Michael
 
Man kann versuchen, das so weit es geht in eine Methode auszulagern:
Java:
public class myclass {
    String s1, s2;

    private static String[] computeSplit(String t) {
        String[] split = t.split(",");
        if (split.length < 2)
            return new String[]{split[0], "defaultstring"};
        else
            return new String[]{split[0], split[1]};
    }

    myclass(String t1, String t2) {
        s1 = t1;
        s2 = t2;
        // weiterer Code
    }

    myclass(String t) {
        this(computeSplit(t)[0], computeSplit(t)[1]);
    }
}
In deinem Fall hängen allerdings beide Argumente für den this(t1, t2) Konstruktoraufruf vom Ergebnis der Berechnung ab.
Hier fällt mir momentan nichts besseres ein, als die Berechnung einfach zweimal zu machen.
 
Entweder lagerst Du den Code in statische Methoden aus, die Du in this(...) aufrufst, oder aber Du schreibst Dir gleich eine Klasse für den Spaß. BTW: Klassennamen beginnen in Java mit einem Großbuchstaben.

Java:
public class MyClass {
    public MyClass(String s1, String s2) {}
    public MyClass(String s) {
        this(new Splitter(s));
    }
    private MyClass(Splitter s) {
        this(s.firstPart(), s.secondPart());
    }

    private static class Splitter {
        private String[] parts;
        Splitter(String s) { parts = s.split(","); }
        public String firstPart() { return parts[0]; }
        public String secondPart() { return parts[1]; }
    }
}
 
Generell gibt es mehrere Möglichkeiten, die in Betracht kommen können:

a) Das ist hier auf eine Standard Refactoring Methode zurück zu führen, bei der Du doppelten Code hast. Sprich: Das was der eine Konstruktor macht ist auch in dem anderen Konstruktor.
Das übliche Vorgehen ist dann, dies in eine separate Methode zu ziehen. Du hast dann also etwas wie:
Java:
public class MyClass {
    public MyClass (String one) {
        // Whatever ...
        doSomething(s1, s2);
    }
    
    public MyClass(String one, String two) {
        // Whatever
        doSomething(s1, s2);
    }
}

Generell gibt es hier aber eine Thematik, die man bedenken muss: Bei Aufrufen im Konstruktor ist die Instanz noch nicht zu Ende Initialisiert. Das kann einige Nebeneffekte haben wenn z.B. so eine Methode überschrieben wird. Daher sollte doSomething final sein.

Aber der Aufbau wird deutlich. s1 / s2 habe ich verwendet, denn bei "Whatever" kann das irgendwie gebildet werden und muss z.B nicht zwingend one / two sein.

b) Konstruktoren, die komplex sind, werden in der Regel vermieden. Statt dessen gibt es dann Factory Methoden. Das sind dann statische Methoden, die eine Instanz zurück geben:

Java:
public class MyClass {
    public MyClass(String one, String two) {
        // Whatever
    }
    
    public static MyClass fromSingleString(String oneStringOnly) {
        // Whatever
        return new MyClass(s1, s2);
    }
}

Das wären so zwei Pattern, die üblich sind.

Generell kann man sich auch überlegen, was man da für eine Komplexität hat. Evtl. ist die Komplexität so hoch, weil das Model, das man erstellt hat, noch zu grob ist. Dann würde man das weiter unterteilen und hat dann ggf. einen vereinfachten Code.
 
Hallo zusammen,
erst mal vielen Dank an alle für die schnellen Antworten. Ich denke, das einfachste für mich wird die Factory-Methode sein, also, wenn ich das richtig verstehe, eine Methode, die eine neue Instanz der Klasse als Rückgabewert hat. Eigentlich ganz logisch.

Die Komplexität ist hier übrigens nicht so hoch, dass sich die Einführung weiterer Klassen lohnen würde. Es sind halt noch 4 oder 5 Zeilen Code und es werden zwei static-Variablen gesetzt, je nach Werten der strings. Es handelt sich auch nur um ein winziges Hobby-Projekt.

VG Michael
 

Zurück
Oben