Frage

In Java, Konstrukteure können nicht rekursiv sein. Compile Zeitfehler: „rekursive Konstruktor Aufruf“. Nehmen wir an, dass wir diese Einschränkung nicht hatte.

Dinge im Auge zu behalten:

  • Der Rückgabetyp eines Konstruktor ist nichtig. Da es sich um eine void-Methode kann man nicht Gurtzeug die komplette Leistung der Rekursion.
  • kann ein Konstruktor aufrufen selbst (oder einen anderen Konstruktor) mit diesem (). Aber ein „Aufruf muss diese erste Anweisung im Konstruktor sein“
  • Wir können nicht lokale Daten zwischen aufeinanderfolgenden Anrufen verwenden, um noch einigen möglichen Gewinn aus rekursiven Konstrukteure haben.

gäbe es keinen Nutzen aus der Gewährung der rekursiven Konstrukteurs?

War es hilfreich?

Lösung

Constructors (wenn sie sich gegenseitig anrufen) sind wie Methoden, die Rückkehr void. Folglich ist der einzige Weg, sie Ergebnisse produzieren kann, ist durch Nebenwirkungen. Dies ist dann begrenzt auf Mutieren des Objekts sie bauen oder durch die Werte Mutieren als Parameter übergeben. Letzteres ist eine ziemlich böse Idee in einem Konstruktor; ein Konstruktor übernimmt in der Regel Informationen aus seinen Parametern, ohne sie zu mutieren.

So das Objekt mutiert aufgebaut ist, ist die einzige Option, um jede mögliche Weise zu haben, um den Fortschritt der Rekursion, um zu verfolgen, für sie schließlich zu beenden. Und es ist sehr schwer zu sehen, wie die leichter zu schreiben wären, klarer zu lesen, usw. als eine einfache Schleife in einem gewöhnlichen Konstruktor.

anderen Konstruktor aufrufen (mit this) aus einem Konstruktor ist natürlich ganz anders als mit einem new Ausdruck in einem Konstruktor:

class Node
{
    Node _left, _right;

    public Node(Node left, Node right)
    {
        _left = left != null ? new Node(left._left, left._right) : null;
        _right = right != null ? new Node(right._left, right._right) : null;
    }
}

Hier ist der Node Konstruktor ruft selbst, sondern über einen neuen Ausdruck . Das ist der entscheidende Unterschied. Ein new Ausdruck erzeugt einen Wert, so dass diese rein „funktional“ ist, nicht mutieren Sachen, und bietet eine bequeme Möglichkeit, eine tiefe Kopie des Baumes von Knoten zu machen.

Andere Tipps

Konstrukteurs können rekursiv sein. (Das ist in C #, aber Sie können das gleiche in Java tun)

Schauen wir uns dieses Problem. Zunächst einmal, was passiert, wenn Sie invoke new MyClass("foo");? Nun gibt es zwei Dinge passiert. Zunächst einmal wird die virtuelle Maschine der Speicher zuweisen benötigten ein Objekt vom Typ MyClass zu speichern. Dann wird der Konstruktor aufgerufen. Die Aufgabe eines Konstruktor ist diese gerade zugewiesenen Speicher zu initialisieren. Daher wird ein Konstruktor keinen Rückgabetyp überhaupt haben (nicht einmal void). Der Wert durch den neuen Betreiber zurückgegeben wird, ist ein Verweis auf den zugewiesenen Speicher, so dass der Konstruktor nicht auch zurückgeben kann.

Dann, was würde der Nutzen der rekursiven Konstruktor Aufruf sein. Der einzige Vorteil solchen Aufruf wäre, bestimmte Konstruktorparameter wie andere zu behandeln, und so durch erneute Berufung auf den Konstruktor zu tun. Während dies möglich ist, ist es in der Regel einfach nur die Werte im Konstruktor anzupassen selbst (nicht-final-Parameter), und danach Initialise Objektattribute (kurz Sie keine Rekursion für diese benötigt).

Zweitens können Sie Rekursion ziemlich leicht tun, indem sie die ganze Arbeit eines Arbeitnehmers Methode Offloading, die so viel Rekursion können, wie Sie möchten.

Eine weitere interessante Frage ist die Beschränkung auf Super- oder dieser Aufruf ist, um die erste Seite Aussage des Konstrukteurs. Diese Beschränkung wurde wahrscheinlich schlampig oder unsichere Programmierpraktiken zu entmutigen setzt in. Statement wird, obwohl in fett hier setzen, wie es möglich ist (wenn auch nicht schön) an der Arbeit um diese Einschränkung. Wenn Sie daran denken, dass Ausdrücke Nebenwirkungen haben kann (zum Beispiel variable Zuweisungen) und Ausdrücke für Parameter aufgerufen werden, bevor der Anruf selbst ist es möglich, komplizierte Ausdrücke zu erstellen, die alle Ihre Berechnungen tun, bevor der Delegat Konstruktor aufgerufen wird.

Der allgemeine Grund, warum Sie einen Delegaten / Super Konstruktor Aufruf später im Konstruktor Körper haben wollen, ist Parameter Manipulation. Sie können mit (statisch) Hilfsfunktionen tun, die diese Berechnungen und die richtigen Werte liefern. Dies ist im Allgemeinen sauberen, aber nicht in allen Fällen. Die tatsächliche Ausführungsgeschwindigkeit sollte nicht betroffen sein als Hotspot diese Dinge Inline kann sehr gut.

Das bedeutet, dass die Betrachtung am Ende nach unten läuft darauf hinaus die Flexibilität der freien Platzierung von Delegierten / Super Anrufen gegen die zusätzliche Sicherheit schwieriger, indem sie falsche Praktiken zur Verfügung gestellt, um die Bereitstellung ziemlich viel. Die Wahl von Java-Designern (und der allgemeinen Java-Philosophie) ist für die es schwerer zu gehen, um die falschen Dinge auf Kosten der rohen Sprache Leistung an der Hand von Experten zu tun (mit erhöhter Komplexität). Die Wahl für mich gemacht ist ein gültiger, wenn auch ich persönlich die Macht möchte (man kann immer eine Java ++ Sprache auf dem JVM implementieren, die nicht diese Einschränkungen hat).

Sie können nicht in der Lage sein, einen rekursiven Konstruktor zu schreiben, aber Sie können eine rekursive Funktion von Ihrem Konstruktor aufrufen. Ich habe noch nie, dies zu tun hatte, und ich kann eine Situation nicht denken, wo Sie brauchen könnten, aber Sie können es tun, wenn Sie wollen.

Was meinst du damit? Sie können in Java rekursive Konstrukteure haben. Sie ermöglichen es, die Wiederverwendung von Code und gestalten Sie Ihre Konstrukteure in einer hierarchischen Weise.

In der folgenden rekursiven Konstruktor Beispiel I new User() oder new User("Marcus") und mit jedem Konstruktor aufrufen können, dass ich verwenden, newUser ist auf true.

public class User() {
  public String userName;
  public boolean newUser;
  User() {
    newUser = true;
  }
  User(String userName) {
    // Recursively call no-argument constructor
    this();
    this.userName = userName;
  }
}

Hier ist die gleiche Sache, ohne rekursive Konstrukteure. Beachten Sie die doppelte Codezeile:

public class User() {
  public String userName;
  public boolean newUser;
  User() {
    newUser = true;
  }
  User(String userName) {
    newUser = true;
    this.userName = userName;
  }
}

In der folgenden nicht-rekursive Konstruktor Beispiel, wenn ich keinen Namen in den Konstruktor übergeben, dann wird der Name auf „Neuer Benutzer“. Ich möchte nur den Konstruktor ohne Argumente nennen, wenn ich nicht den Namen zu setzen. Wenn ich einen rekursiven Konstruktoraufruf hier täte, würde ich die Benutzername am Ende Einstellung zweimal:

public class User() {
  public String userName;
  User() {
    this.userName = "New User";
  }
  User(String userName) {
    this.userName = userName;
  }
}

Sie werden nur rekursive Konstrukteuren, wenn Sie verwenden:

  1. Haben Sie mehr als einen Konstruktor
  2. Haben Sie Code in Ihre Konstrukteure
  3. Möchten Sie rekursiv Verwendung Code, der in einem anderen Konstruktor
  

Der Rückgabetyp eines Konstruktor   nichtig.

Nein, es ist nicht.

  

kann ein Konstruktor aufrufen selbst (oder einen anderen Konstruktor) mit dieser ()

Nein. Es kann nur invoke andere Konstrukteuren, und nur, wenn diese nicht zu einem rekursiven Aufruf des aktuellen Konstruktor führen. Deshalb sollten Sie die Fehlermeldung bezeichnet Sie.

  

Wir konnten nicht lokale Daten verwenden, um zwischen   aufeinanderfolgende Anrufe müssen noch einige   möglicher Gewinn aus rekursiven   Konstrukteure.

Wie? Warum wollen Sie auf re ein Objekt -initialize? Wann können Sie es nicht nacheinander in einem Durchgang tun? Noch nie hatte dieses Problem in 39 Jahren Computerprogrammierung und 20 Jahren OO.

  

gäbe es keinen Nutzen aus   so dass rekursive Konstrukteurs?

Sie gekommen sind, nicht mit ...

nach oben
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top