2016-07-14 13 views
1

Wie wir im Konstruktorhauptteil einer Unterklasse wissen, muss der Elternkonstruktor die erste Anweisung sein, andernfalls erhalten wir einen Kompilierzeitfehler. Dieses Thema wurde bereits behandelt here.Überprüfen Sie die Bedingungen in der Unterklasse vor dem Aufruf der Superklassenkonstruktormethode

Nehmen wir an, dass den Aufruf der Mutter Konstruktor hohe Kosten der Systemressourcen verursacht, in anderen in der Unterklasse Konstruktor wir zunächst einige Bedingungen überprüfen müssen, wenn die Bedingungen erfüllt sind sind wir gut zu gehen durch die Mutter Konstruktor sonst gibt es keine Notwendigkeit, weiter zu gehen (sagen wir mal eine Ausnahme):

class parent { 
    parent(Object blah) { 
     //Heavy resource consuming tasks 
    } 
} 

class child extends parent { 
    child(Object blah, boolean condition) { 
     if (!condition) throw new IllegalArgumentException("Condition not satisfied"); 
     super(blah); //Compile error! 
    } 
} 

Wenn jemand das gleiche Problem hatte ich neugierig bin, ist es trotzdem mit dieser Situation zu umgehen oder muss ich die Mutter Konstruktor aufrufen zuerst Egal wie viele Ressourcen es verschwendet und dann die Ausnahme auslöst?

+2

Mögliches Duplikat von [Warum muss this() und super() die erste Anweisung in einem Konstruktor sein?] (Http://stackoverflow.com/questions/1168345/why-does-sthis-and-super- have-to-be-the-first-Anweisung-in-a-constructor) – CollinD

+1

Legen Sie keine solche ressourcenintensive Logik in den Konstruktor. Erstellen Sie einen leichtgewichtigen Konstruktor und eine separate 'init()' Methode, um das schwere Heben durchzuführen. – azurefrog

+0

@azurefrog so, wenn ich init() ich muss immer noch den Elternkonstruktor an erster Stelle –

Antwort

6

Sie so etwas tun könnte:

public class Jlaj extends ArrayList<String> { 

    public Jlaj(int capacity) { 
     super(checkCapacity(capacity)); 
    } 

    private static int checkCapacity(int capacity) { 
     if (capacity > 1000) 
      throw new IllegalArgumentException(); 
     return capacity; 
    } 

    public static void main(String[] args) { 
     new Jlaj(1001); // this throws IAE all right 
    } 
} 

Beachten Sie, dass Sie nur statische Methoden auf diese Weise aufrufen können, und das ist gut so: auf einem teilweise initialisierte Objektinstanz Methoden aufrufen ist bereits eine sehr große Mühe, sie fordern schon vor Superklassenbauern wäre das ein Albtraum.

Was nun, wenn Sie einige andere Argumente überprüfen müssen, die Sie nicht an die Oberklasse übergeben? Sie könnten so etwas dann tun:

public class Jlaj extends ArrayList<String> { 

    private final Object foo; 

    public Jlaj(int capacity, Object foo) { 
     super(checkArgumentsAndReturnCapacity(capacity, foo)); 
     this.foo = foo; 
    } 

    private static int checkArgumentsAndReturnCapacity(int capacity, Object foo) { 
     if (capacity > 1000) 
      throw new IllegalArgumentException(); 
     if (foo == null) 
      throw new NullPointerException(); 
     return capacity; 
    } 

    public static void main(String[] args) { 
     new Jlaj(1000, null); // throws NPE 
    } 
} 

Es funktioniert, aber sieht ein bisschen hässlich aus. Sie übergeben zwei nicht verwandte Dinge in eine Funktion, die nur ein Argument für die Oberklasse zurückgibt. Zumindest der beschreibende Name gleicht das etwas aus.

+0

Danke, das ist genau das, was ich gesucht habe –

+0

Was ist, wenn die Anzahl der Argumente der Unterklasse und Superklasse Konstruktor nicht übereinstimmen? Funktioniert Ihre Lösung auch in diesem Szenario oder sollte ich eine Builder-Methode wie Cyril verwenden? –

+1

@FarShaD, naja, technisch kann es funktionieren, wird aber hässlich aussehen. Fügt ein Beispiel in einem Moment hinzu. –

2

wenn Sie unbedingt das tun müssen, können Sie eine statische Builder-Methode mit einem privaten Konstruktor erstellen:

class child extends parent { 
    private child(Object blah) { 
     super(blah); 
    } 

    static child create(Object blah, boolean condition) { 
     if (!condition) throw new IllegalArgumentException("Condition not satisfied"); 

     return new child(blah); 
    } 


    public static void main(String[] args) { 
     child a = child.create("a", true); 
    } 
} 

Ich bin kein Fan von einer separaten init-Methode, weil Sie mit ungültigem Zustand werden am Ende wenn du vergisst, es anzurufen.

+0

Danke für die Antwort, statische Methoden sind in meinem Fall geeignet –

+0

Der Vorteil dieser Lösung ist, dass es immer funktioniert, egal wie viele Argumente Unterklasse Konstruktor haben. –