2686 Stimmen

Wie rufe ich in Java einen Konstruktor von einem anderen aus auf?

Ist es möglich, einen Konstruktor von einem anderen aufzurufen (innerhalb der gleichen Klasse, nicht von einer Unterklasse)? Wenn ja, wie? Und was könnte der beste Weg sein, einen anderen Konstruktor aufzurufen (wenn es mehrere Möglichkeiten gibt)?

2 Stimmen

Ich glaube, die Prämisse Ihrer Frage ist falsch. Anstatt einen Konstruktor innerhalb eines Konstruktors aufzurufen, verwenden Sie das Factory-Muster. Eine statische Factory-Methode erstellt zunächst alle Objekte der unteren Ebene. Dann werden die Objekte der höheren Ebene konstruiert, die vom Factory-Aufruf zurückgegeben werden. Durch diese Technik wird die Komplexität des Modells verringert, was die Wartung, die Klarheit und das Testen erleichtert.

1 Stimmen

Ich bin im Allgemeinen zu privaten Konstruktoren und Fabrikmethoden übergegangen, da Konstruktoren aufgrund ihrer Beschränkungen das Prinzip des offenen und geschlossenen Systems verletzen. Ich denke, dieser Kommentar sollte die richtige Antwort sein, alles andere wird Ihre Teamkollegen nur verwirren.

0 Stimmen

Sroy, aber das ist keine gute Praxis, wenn Sie so etwas tun wollen, überladen Sie den Konstrukteur. Wenn Sie einen Inhalt verpacken möchten, könnte das getan werden, aber für einen anderen Zweck. Nicht der Konstruktor public class Foo { private int x; public Foo() { } public Foo(int x) { this.x = x; } public Foo(int x, int y) { this.x = x; this.y = y }

3405voto

Jon Skeet Punkte 1325502

Ja, das ist möglich:

public class Foo {
    private int x;

    public Foo() {
        this(1);
    }

    public Foo(int x) {
        this.x = x;
    }
}

Um eine Verkettung mit einem bestimmten Oberklassenkonstruktor anstelle eines Konstruktors in derselben Klasse durchzuführen, verwenden Sie super 代わりに this . Beachten Sie, dass können Sie nur mit einem Konstruktor verketten y es muss die erste Anweisung im Konstruktorkörper sein .

Siehe auch diese verwandte Frage in dem es zwar um C# geht, für den aber die gleichen Grundsätze gelten.

40 Stimmen

Ich nehme also an, dass es nicht möglich ist, einen Superkonstruktor und einen anderen Konstruktor der gleichen Klasse aufzurufen, da beide die erste Zeile sein müssen?

39 Stimmen

@gsingh2011: In der Tat. Sie können nur verketten zu eine anderen Konstrukteur.

53 Stimmen

Dies muss in der ersten Zeile stehen, aber Sie können Berechnungen im Konstruktor durchführen, bevor dieser aufgerufen wird: Sie können statische Methoden in den Argumenten von this() in der ersten Zeile verwenden und jede Berechnung, die vor dem Aufruf des anderen Konstruktors durchgeführt werden muss, in dieser statischen Methode kapseln. (Ich habe dies als separate Antwort hinzugefügt).

301voto

Josh Punkte 16859

Verwendung von this(args) . Das bevorzugte Muster ist, vom kleinsten Konstruktor zum größten zu arbeiten.

public class Cons {

    public Cons() {
        // A no arguments constructor that sends default values to the largest
        this(madeUpArg1Value,madeUpArg2Value,madeUpArg3Value);
    }

    public Cons(int arg1, int arg2) {
       // An example of a partial constructor that uses the passed in arguments
        // and sends a hidden default value to the largest
        this(arg1,arg2, madeUpArg3Value);
    }

    // Largest constructor that does the work
    public Cons(int arg1, int arg2, int arg3) {
        this.arg1 = arg1;
        this.arg2 = arg2;
        this.arg3 = arg3;
    }
}

Sie können auch einen neueren Ansatz von valueOf oder einfach "of" verwenden:

public class Cons {
    public static Cons newCons(int arg1,...) {
        // This function is commonly called valueOf, like Integer.valueOf(..)
        // More recently called "of", like EnumSet.of(..)
        Cons c = new Cons(...);
        c.setArg1(....);
        return c;
    }
} 

Um eine Superklasse aufzurufen, verwenden Sie super(someValue) . Der Aufruf von super muss der erste Aufruf im Konstruktor sein, sonst erhalten Sie einen Compilerfehler.

35 Stimmen

Wenn viele Konstruktorparameter verwendet werden, sollte ein Builder in Betracht gezogen werden. Siehe Punkt 2 von "Effective Java" von Joshua Bloch.

6 Stimmen

Das Problem bei der Umsetzung des letzten Ansatzes mit Hilfe der Fabrikmethode, newCons ist, dass Sie versuchen, den Zustand eines Objekts zu ändern, indem Sie setArg1(...) die höchstwahrscheinlich ihre Felder als endgültig festgelegt haben sollten. Da wir versuchen, so viel wie möglich von einem Objekt unveränderlich zu halten, wenn auch nicht vollständig, wird ein Builder-Muster dieses Problem besser lösen.

2 Stimmen

Würden Sie nicht lieber :: public Cons() { this(madeUpArg1Value,madeUpArg2Value); }

243voto

Christian Fries Punkte 14995

[ Anmerkung: Ich möchte nur einen Aspekt hinzufügen, den ich in den anderen Antworten nicht gesehen habe: Wie kann man die Einschränkungen der Anforderung überwinden, dass this() in der ersten Zeile stehen muss?) ]

In Java kann ein anderer Konstruktor der gleichen Klasse von einem Konstruktor über this() . Beachten Sie jedoch, dass this muss in der ersten Zeile stehen.

public class MyClass {

  public MyClass(double argument1, double argument2) {
    this(argument1, argument2, 0.0);
  }

  public MyClass(double argument1, double argument2, double argument3) {
    this.argument1 = argument1;
    this.argument2 = argument2;
    this.argument3 = argument3;
  }
}

Das this in der ersten Zeile stehen muss, sieht wie eine große Einschränkung aus, aber Sie können die Argumente anderer Konstruktoren über statische Methoden konstruieren. Zum Beispiel:

public class MyClass {

  public MyClass(double argument1, double argument2) {
    this(argument1, argument2, getDefaultArg3(argument1, argument2));
  }

  public MyClass(double argument1, double argument2, double argument3) {
    this.argument1 = argument1;
    this.argument2 = argument2;
    this.argument3 = argument3;
  }

  private static double getDefaultArg3(double argument1, double argument2) {
    double argument3 = 0;

    // Calculate argument3 here if you like.

    return argument3;

  }

}

16 Stimmen

Es stimmt, dass man auf diese Weise statische Methoden aufrufen kann, um komplexe Berechnungen für Argumentwerte durchzuführen, was in Ordnung ist. Wenn man jedoch der Meinung ist, dass Code vor der Delegation des Konstruktors benötigt wird ( this(...) ), dann wäre es vernünftig anzunehmen, dass irgendwo ein schrecklicher Fehler gemacht wurde und dass das Design vielleicht ein wenig überdacht werden muss.

16 Stimmen

Ich würde zustimmen, dass ein sehr komplexe Umwandlung weist wahrscheinlich auf ein Designproblem hin. Aber 1) gibt es einige einfache Transformationen, für die dies nützlich sein kann - nicht alle Konstruktoren sind nur lineare Projektionen auf andere und 2) kann es andere Situationen geben, in denen diese Informationen nützlich sein könnten, wie die Unterstützung von Legacy-Code. (Ich stimme zwar mit Ihrer Schlussfolgerung überein, sehe aber nicht, warum dies eine Ablehnung rechtfertigen würde).

2 Stimmen

@RodneyP.Barbati: Ich sehe ein paar Probleme, wenn man es so macht, wie du es beschreibst: a) Wenn man es so macht, ist es nicht möglich, die Verwendung einer statischen Methode in einem Konstruktor zu illustrieren (und das ist die Absicht des Beispiels) ;-) und b) wenn man es so macht, können die Felder nicht final (endgültige Felder können nur einmal initialisiert werden).

44voto

Kaamel Punkte 1812

Wenn ich einen anderen Konstruktor innerhalb des Codes aufrufen muss (nicht in der ersten Zeile), verwende ich normalerweise eine Hilfsmethode wie diese:

class MyClass {
   int field;

   MyClass() {
      init(0);
   } 
   MyClass(int value) {
      if (value<0) {
          init(0);
      } 
      else { 
          init(value);
      }
   }
   void init(int x) {
      field = x;
   }
}

Meistens versuche ich jedoch, es andersherum zu machen, indem ich die komplexeren Konstruktoren von den einfacheren in der ersten Zeile aufrufe, soweit dies möglich ist. Für das obige Beispiel

class MyClass {
   int field;

   MyClass(int value) {
      if (value<0)
         field = 0;
      else
         field = value;
   }
   MyClass() {
      this(0);
   }
}

33voto

amila isura Punkte 980

Innerhalb eines Konstruktors können Sie die this Schlüsselwort, um einen anderen Konstruktor in derselben Klasse aufzurufen. Dies wird als expliziter Konstruktoraufruf .

Hier ist eine weitere Rectangle-Klasse, deren Implementierung sich von der im Abschnitt "Objekte" unterscheidet.

public class Rectangle {
    private int x, y;
    private int width, height;

    public Rectangle() {
        this(1, 1);
    }
    public Rectangle(int width, int height) {
        this( 0,0,width, height);
    }
    public Rectangle(int x, int y, int width, int height) {
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
    }

}

Diese Klasse enthält eine Reihe von Konstruktoren. Jeder Konstruktor initialisiert einige oder alle der Mitgliedsvariablen des Rechtecks.

1 Stimmen

Warum rufen Sie nicht den zweiten Konstruktor auf, der lautet Rectangle(int width, int height) en Rectangle() anstelle von Rectangle(int x, int y, int width, int height) ?

1 Stimmen

@RodneyP.Barbati In diesem Fall kann ich nicht zustimmen. Dieses Muster lässt keine endgültigen Felder zu.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X