2016-07-20 5 views
1

Ich habe erst vor kurzem angefangen, Java zu lernen, und in meinem Lehrbuch bin ich auf this gestoßen, was anfangs sehr verwirrend war, aber jetzt beginnt es Sinn zu ergeben. Nun, in meinem Buch wir gestartet grundlegende Anwendungen von Konstruktoren und als Randnotiz auf der Seite sagte this, kann auch verwendet werden, um andere Konstruktoren aufzurufen. Ich war ein wenig verwirrt, dann Blick auf andere Fragen zu SO bezüglich this. Ich denke, ich verstehe es jetzt schon, aber WARUM würde ich das jemals tun wollen? Betrachten Sie das Folgende, das ich gerade erfunden habe.Warum sollte ich jemals einen Konstruktor von einem anderen (Java) aufrufen?

private double balance; 
private double interest; 
public Account(double initialBalance){ 
    balance = initialBalance; 

} 
public Account(double balance, double interest){ 
    this(0); 
    balance = initialBalance; 
    this.interest = interest; 
} 

Hier this(0);, um mein Verständnis für einen anderen Konstruktor mit einem Parameter sucht, findet Account(double initialBalance) und setzt initialBalance auf Null. Großartig. Ähm, aber warum sollte ich das nicht direkt machen? Stellen Sie den Saldo gleich Null ein! Ich bin mir sicher, dass es sehr nützlich ist, aber ich kann mir keine Beispiele vorstellen. Danke!

+0

ob man es so schreiben oder nicht, sind Sie immer. Die erste Anweisung aus einem (ny) -Konstruktor besteht darin, einen/den Konstruktor der Elternklasse – Stultuske

+2

@Stultuske aufzurufen. Dies hat nichts mit der Elternklasse zu tun. Kein Wortspiel beabsichtigt. – Zircon

+0

@Zircon: Rufen Sie einen anderen Konstruktor ... was ist im Grunde, was ich beschrieben habe. Wenn es aus der gleichen Klasse stammt, ist der Code, den er gepostet hat, entweder nicht der Code aus seinem Buch, oder sie benutzten es als Beispiel dafür, was nicht zu tun ist, oder es ist ein beschissenes Buch. – Stultuske

Antwort

3

Das Beispiel von Java documentation wird wahrscheinlich viel mehr Sinn als die, die Sie in Ihren Händen machen:

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

    public Rectangle() { 
     this(0, 0, 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; 
    } 
    ... 
} 
0

Dies wird "Konstruktorüberladung" genannt. Genau wie das Überladen von Methoden ermöglicht Ihnen Java, verschiedene Parameter für eine einzige Methode bereitzustellen.

Es wird im Allgemeinen für Methoden oder in diesem Fall Konstruktoren verwendet, die "optionale" Parameter haben.

class Cat{ 
    private int paws; 
    private String name; 

    public Cat(String name){ 
     //Assume that the cat is physically not handicapped, and thus has 4 paws 
     this(name,4); 
    } 

    public Cat(String name, int paws){ 
     this.name = name; 
     this.paws = paws; 
    } 
} 
1

Denken Sie darüber, dass Sie es in die andere Richtung tun könnte: Heres ein Beispiel, das es noch deutlicher machen sollte Ihr „basic“ Konstruktor ist

public Account(double balance, double interest){ 
    balance = initialBalance; 
    this.interest = interest; 
} 

und auf dieser Basis könnten Sie einige hinzufügen Vereinfachungen:

Der Aufruf dieser Konstruktoren vereinfacht die Änderung des Hauptverhaltens: wenn ich, e. Ich möchte das neue Objekt irgendwo registrieren, ich kann das an einem zentralen Ort tun und die anderen Konstrukteure müssen sich darauf verlassen.

+0

Müssen wir nicht DEFAULT_INTEREST, DEFAULT_INITIAL_BALANCE definieren? –

+0

@cresjoy Was hindert uns daran? – glglgl

+0

wo soll ich sie definieren? Mache ich sie nur Instanzvariablen? –

0

Es würde mehr Sinn machen, wenn Sie es umgekehrt stellen.

public Account(double initialBalance){ 
    this(initialBalance, 2.0); // 2.0 being a default interest (whatever you'd like, could be 0). 
} 

public Account(double balance, double interest){ 
    this.balance = balance; 
    this.interest = interest; 
    // Some more very difficult business logic 
} 

Auf diese Weise können Sie doppelten Code verhindern. Eine Änderung der schwierigen Geschäftslogik müsste nur einmal geändert werden (falls erforderlich).

1

Hier ist ein gutes Beispiel anderen Konstruktor des gleichen Objekts zu verwenden:

public Person(String name, String street, String location) { 
    (...) 
    //handle them 
} 

public Person() { 
    this("default name", "default street", "default location"); 
} 

Es ist im Grunde eine Abkürzung (Überlastung), so dass Sie frei von redundantem Code bleiben.

1

Dieses Beispiel macht in der Tat nicht viel Sinn.

Folgendes tut.

private double balance; 
private double interest; 

public Account(double initialBalance){ 
    this(initialBalance, 9.99); 
} 

public Account(double balance, double interest){ 
    this.balance = balance; 
    this.interest = interest; 
} 

Und in der Tat ruft man einen anderen Konstruktor, der in der Regel einige Arbeit als nur zuweisen tut.

Für das ursprüngliche Beispiel könnte es sein, dass der einfache Konstruktor zuerst erstellt wurde und später der Konstruktor mit dem zusätzlichen Argument für ein zusätzliches Feld interest hinzugefügt wurde.

So könnte man dieses Konstrukt sehen oft, und es ist vergleichbar mit Aufrufen an super(...)

Auch in einfachen Fällen folgt dieser Gebrauch das DRY-Prinzip: Sie sich nicht wiederholen. Wenn einer der Konstruktoren nur ein paar verschiedene Zuordnungen in der Zeit hatte, würde das Programm vom Konstruktor abhängig sein. Jetzt wissen Sie, dass derselbe Code durchlaufen wird und Sie diese Funktionalität nicht N-mal testen müssen.

5

Es ist sehr praktisch und vermeidet Code-Duplizierung:

public Account(){ 
    this(0); 
} 

public Account(double initialBalance){ 
    this(initialBalance, DEFAULT_INTEREST_RATE); 
} 

public Account(double balance, double interest){ 
    balance = initialBalance; 
    this.interest = interest; 
} 

Die Konstrukteure mit weniger Argumente Delegierter Konstrukteuren mit mehr Argumente, Standardwerte für die fehlenden Argumente zu übergeben.

Wenn dies nicht möglich wäre, würde man eine künstliche init(..) Methode benötigen, die die Parameter akzeptiert und von allen Konstruktoren aufgerufen wird. Dies ist weniger sicher, da diese Methode wiederholt aufgerufen werden könnte.

+0

Könntest du etwas erweitern, würde man eine künstliche Init (..) brauchen, oder ist das etwas, was ich später lernen werde? –

+1

Was @Peter bedeutet, ist, dass, wenn Java einem Konstruktor nicht erlaubt, einen anderen Konstruktor aufzurufen, eine Möglichkeit zur Vermeidung von Codeverdopplung in mehreren Konstruktoren darin besteht, dass jeder der Konstruktoren nur eine einzige Methode aufruft, die den Code ausführt, der ansonsten dupliziert würde . Er nennt diese Methode "init". Dies ist nicht sicher, da diese Methode auch an anderer Stelle in der Klasse aufgerufen werden könnte. – FredK

+0

genau was @FredK sagte ^^ –

1

Überlastung Bauer praktisch oft kommen. Ein Beispiel ist, wenn Sie mehrere Argumente haben, aber nicht alle sind obligatorisch.

Überlastung Verwenden Sie so etwas wie zu tun:

public Account(string id, double balance, string name, strings address){ 
    this.id = id; 
    this.balance = balance; 
    this.name = name; 
    this.address = address; 
} 

public Account(string id, double balance, string name){ 
    this(id, balance, name, null); 
} 

public Account(string id, double balance){ 
    this(id, balance, "Unknown" ,null); 
} 

public Account(string id){ 
    this(id, 0, "Unknown" ,null); 
} 
Verwandte Themen