Wann sollte ich "dies" in einer Klasse verwenden?

267

Ich weiß, dass thissich das auf ein aktuelles Objekt bezieht. Aber ich weiß nicht, wann ich es wirklich brauchen muss. Gibt es zum Beispiel einen Unterschied, wenn ich einige Methoden xanstelle von this.xverwende? Vielleichtx , auf eine Variable beziehen , die für die in Betracht gezogenen Methode lokal ist? Ich meine Variable, die nur in dieser Methode gesehen wird.

Was ist mit this.method()? Kann ich es benutzen? Soll ich es benutzen? Wenn ich nur verwende method(), wird es nicht standardmäßig auf das aktuelle Objekt angewendet?

römisch
quelle

Antworten:

346

Das thisSchlüsselwort wird hauptsächlich in drei Situationen verwendet. Die erste und häufigste Methode sind Setter-Methoden zur eindeutigen Unterscheidung von Variablenreferenzen. Die zweite Möglichkeit besteht darin, die aktuelle Klasseninstanz als Argument an eine Methode eines anderen Objekts zu übergeben. Die dritte Möglichkeit besteht darin, alternative Konstruktoren innerhalb eines Konstruktors aufzurufen.

Fall 1: Verwenden thiszum Disambiguieren von Variablenreferenzen. In Java-Setter-Methoden übergeben wir normalerweise ein Argument mit demselben Namen wie die private Mitgliedsvariable, die wir festlegen möchten. Wir weisen dann das Argument xzu this.x. Dies macht deutlich, dass Sie der Instanzvariablen "name" den Wert des Parameters "name" zuweisen.

public class Foo
{
    private String name;

    public void setName(String name) {
        this.name = name;
    }
}

Fall 2: Verwendung thisals Argument, das an ein anderes Objekt übergeben wird.

public class Foo
{
    public String useBarMethod() {
        Bar theBar = new Bar();
        return theBar.barMethod(this);
    }

    public String getName() {
        return "Foo";
    }
}

public class Bar
{
    public void barMethod(Foo obj) {
        obj.getName();
    }
}

Fall 3: Verwenden von thisalternativen Konstrukteuren zu nennen. In den Kommentaren wies Trinithis korrekt auf eine andere häufige Verwendung von hin this. Wenn Sie mehrere Konstruktoren für eine einzelne Klasse haben, können Sie this(arg0, arg1, ...)einen anderen Konstruktor Ihrer Wahl aufrufen, sofern Sie dies in der ersten Zeile Ihres Konstruktors tun.

class Foo
{
    public Foo() {
        this("Some default value for bar");

        //optional other lines
    }

    public Foo(String bar) {
        // Do something with bar
    }
}

Ich habe auch gesehen this, wie betont wurde, dass auf eine Instanzvariable verwiesen wird (ohne dass eine Disambiguierung erforderlich ist), aber das ist meiner Meinung nach ein seltener Fall.

William Brendel
quelle
21
+1 Für zu erwähnen , dass Sie auch passieren kann dies als Argument. Dies wird nicht nur zur Disambiguierung des Gültigkeitsbereichs verwendet.
Alex Jasmin
12
Natürlich gibt es auch this(arg1, arg2, ...)einen Konstruktor.
Thomas Eding
12
@Hazior: Ich neige dazu, eine kurze Antwort zu schreiben und sie dann im Laufe der Zeit zu ergänzen. Manchmal überschneidet sich das mit den Antworten anderer Leute, manchmal nicht. Bei meiner letzten Bearbeitung wies Trinithis auf eine andere häufige Verwendung hin this, die ich vergessen hatte, und fügte sie meiner Antwort hinzu. Ich sehe daran nichts auszusetzen, da das Endergebnis insgesamt eine bessere Antwort ist, was genau der Zweck von SO ist. Ich versuche auch, wo immer möglich, Anerkennung zu geben, wie ich es bei Trinithis getan habe.
William Brendel
4
Sie haben Beispiele für Fall 1 und 3. Können Sie bitte ein Beispiel für Fall 2 geben, in dem die aktuelle Klasseninstanz als Argument für eine Methode einer anderen Klasse verwendet wird?
dbconfession
4
@AStar In den meisten Java-Codebasen, mit denen ich im Laufe der Jahre gearbeitet habe, thiswird sie nur verwendet, wenn eine Disambiguierung wirklich erforderlich ist, wie in meinem obigen Setter-Beispiel. Codierungsstile und "Best Practices" können natürlich stark variieren, je nachdem, wen Sie fragen. Im Allgemeinen empfehle ich jedoch, vernünftige Muster auszuwählen und diese einzuhalten. Konsistenz, auch nur intern innerhalb einer einzelnen Codebasis, trägt wesentlich zur Lesbarkeit und Wartbarkeit bei.
William Brendel
71

Die zweite wichtige Verwendung von this(neben dem Verstecken mit einer lokalen Variablen, wie viele Antworten bereits sagen) ist der Zugriff auf eine äußere Instanz von einer verschachtelten nicht statischen Klasse aus:

public class Outer {
  protected int a;

  public class Inner {
    protected int a;

    public int foo(){
      return Outer.this.a;
    }

    public Outer getOuter(){
      return Outer.this;
    }
  }
}
Christopher Oezbek
quelle
46

Sie müssen nur verwenden this - und die meisten Leute verwenden es nur -, wenn es eine überlappende lokale Variable mit demselben Namen gibt. (Setter-Methoden zum Beispiel.)

Ein weiterer guter Grund für die Verwendung thisist natürlich, dass Intellisense in IDEs angezeigt wird :)

froadie
quelle
1
Aber dann müssen Sie es zurücksetzen, nachdem Sie es nachgeschlagen haben. Das Programmieren ist anstrengend!
LegendLength
25

Die einzige Notwendigkeit , das verwenden , this.Qualifier ist , wenn eine andere Variable in den aktuellen Bereich Aktien den gleichen Namen , und Sie möchten die Instanz Mitglied beziehen (wie William beschreibt). Abgesehen davon gibt es keinen Unterschied im Verhalten zwischen xund this.x.

Adam Robinson
quelle
3
Und wenn Sie doppelte Namen haben, sollte eine Ihrer Variablen umbenannt werden, da sie fast definitiv falsch benannt ist. Oder könnte zumindest besser benannt werden.
CaffGeek
3
@Chad: Es ist gängige Praxis in Java-Setter-Methoden. Außerhalb von Setter-Methoden gelten Ihre Aussagen jedoch im Allgemeinen.
William Brendel
2
Vielleicht möchten Sie this.xIhren Code auch ein wenig klarer lesen lassen. Die Wartbarkeit / Lesbarkeit des Codes ist auch ein Faktor, den Sie berücksichtigen sollten ...
Bryan Rehbein
1
@Chad: Ich kann nicht begeistert genug zustimmen. Mein Gott, nur weil "das". ermöglicht es Ihnen, zwei verschiedenen Variablen den gleichen Namen zu geben. Warum möchten Sie das?
BlairHippo
2
@Blair: Wenn Sie Ihre Antwort lesen, wird deutlich, dass Sie diese Praxis bei Setter-Methoden nicht bevorzugen, aber viele Menschen (ich würde mich in diese Liste aufnehmen). Wenn ich eine Setter-Methode habe, die einen Wert annimmt, muss der übergebene Wert eindeutig der "neue" Wert sein. Das Hinzufügen von "new" zum Variablennamen scheint der öffentlichen API unnötige Redundanz hinzuzufügen.
Adam Robinson
15

"this" ist auch nützlich, wenn Sie einen Konstruktor von einem anderen aufrufen:

public class MyClass {
    public MyClass(String foo) {
        this(foo, null);
    }
    public MyClass(String foo, String bar) {
        ...
    }
}
Benjamin
quelle
11

this ist im Builder-Muster nützlich.

public class User {

    private String firstName;
    private String surname;

    public User(Builder builder){
        firstName = builder.firstName;
        surname = builder.surname;
    }

    public String getFirstName(){
        return firstName;
    }

    public String getSurname(){
        return surname;
    }

    public static class Builder {
        private String firstName;
        private String surname;

        public Builder setFirstName(String firstName) {
            this.firstName = firstName;
            return this;
        }

        public Builder setSurname(String surname) {
            this.surname = surname;
            return this;
        }

        public User build(){
            return new User(this);
        }

    }

    public static void main(String[] args) {
        User.Builder builder = new User.Builder();
        User user = builder.setFirstName("John").setSurname("Doe").build();
    }

}
Kieren Dixon
quelle
1
Dies war die Art von Antwort, die ich wollte, als ich gesucht habe und hier gelandet bin, aber Sie haben keine Erklärung für Ihren Code, so dass die meisten Leute, die nach "dies" fragen, nicht verstehen, was "neuen Benutzer (dies) zurückgeben"; bedeutet, wie ich nicht ...
nckbrz
Das Builder-Muster wird verwendet, um Parameter bei der Konstruktion klar anzugeben. Anstatt einen neuen Benutzer (Zeichenfolge, Zeichenfolge) zu haben, bei dem nicht leicht zu erkennen ist, welche Zeichenfolge welche war, hätten Sie einen neuen Builder (). SetFirstName ("Jane"). SetSurname ("Smith"). Build (). Sie geben dies von den Funktionen Builder.set ... () zurück, damit Sie sie verketten können.
ChrisPhoenix
10

Es gibt viele gute Antworten, aber es gibt noch einen sehr kleinen Grund, thisüberall zu setzen . Wenn Sie versucht haben, Ihre Quellcodes mit einem normalen Texteditor (z. B. Notizblock usw.) zu öffnen, verwenden Siethis wird das Lesen durch viel einfacher.

Stell dir das vor:

public class Hello {
    private String foo;

    // Some 10k lines of codes

    private String getStringFromSomewhere() {
        // ....
    }

    // More codes

    public class World {
        private String bar;

        // Another 10k lines of codes

        public void doSomething() {
            // More codes
            foo = "FOO";
            // More codes
            String s = getStringFromSomewhere();
            // More codes
            bar = s;
        }
    }
}

Dies ist mit jeder modernen IDE sehr klar zu lesen, aber mit einem normalen Texteditor ist dies ein Albtraum.

Sie werden Schwierigkeiten haben, herauszufinden, wo sich der fooSpeicher befindet, bis Sie die Suchfunktion des Editors verwenden. Dann wirst du getStringFromSomewhere()aus dem gleichen Grund anschreien . Schließlich, nachdem Sie vergessen haben, was sist, bar = swird das Ihnen den letzten Schlag geben.

Vergleichen Sie es damit:

public void doSomething() {
    // More codes
    Hello.this.foo = "FOO";
    // More codes
    String s = Hello.this.getStringFromSomewhere();
    // More codes
    this.bar = s;
}
  1. Sie wissen, dass fooes sich um eine in der äußeren Klasse deklarierte Variable handelt Hello.
  2. Sie wissen, dass getStringFromSomewhere()es sich auch um eine Methode handelt, die in der äußeren Klasse deklariert ist.
  3. Sie wissen, dass dies barzur WorldKlasse gehört und seine lokale Variable ist, die in dieser Methode deklariert ist.

Wenn Sie etwas entwerfen, erstellen Sie natürlich Regeln. So , während die API oder Projekt entwerfen, wenn Ihre Regeln sind „ wenn jemand öffnet alle diese Quellcodes mit einem Notizblock, sollte er oder sie ihn erschießen / sich in den Kopf,“ dann sind Sie völlig in Ordnung , nicht zu tun dies .

Jai
quelle
tolle Antwort @Jai
Gaurav
Der erste Grund für das Schießen wäre das Schreiben von Klassen mit mehreren 10.000 Zeilen Code, insbesondere wenn der Code bereits in verschiedene Klassen aufgeteilt ist, die nicht verschachtelt werden müssen :)
LuCio
@ LuCio Lol true xD
Jai
7

Sofern Sie keine überlappenden Variablennamen haben, dient dies nur der Übersichtlichkeit beim Lesen des Codes.

ChickenMilkBomb
quelle
1
Wenn Sie ständig das thisSchlüsselwort sehen, wenn es nicht erforderlich ist, ist es nur Boilerplate-Code, der das Lesen des Codes erschwert.
AxeEffect
Ich bin gerade auf ein Open-Source-Projekt gestoßen, das verlangt, dass allen Mitgliedern das Präfix "this" vorangestellt wird. Abgesehen davon ist das Projekt sehr gut geschrieben, aber ich bin versucht, mit ihnen in eine religiöse Debatte zu geraten.
LegendLength
4
@AxeEffect Ich weiß, dass dies wirklich alt ist, aber ... thismacht es NICHT schwieriger, den Code lmao zu lesen.
Xatenev
4

Die Antwort von @William Brendel lieferte drei verschiedene Anwendungsfälle auf nette Weise.

Anwendungsfall 1:

Die offizielle Java-Dokumentationsseite auf dieser Seite bietet dieselben Anwendungsfälle.

Innerhalb einer Instanzmethode oder eines Konstruktors ist dies eine Referenz auf das aktuelle Objekt - das Objekt, dessen Methode oder Konstruktor aufgerufen wird. Sie können mit einer Instanzmethode oder einem Konstruktor auf jedes Mitglied des aktuellen Objekts verweisen, indem Sie dies verwenden.

Es werden zwei Beispiele behandelt:

Verwenden Sie dies mit einem Feld und Verwenden Sie dies mit einem Konstruktor

Anwendungsfall 2:

Anderer Anwendungsfall, der in diesem Beitrag nicht zitiert wurde: thisKann zum Synchronisieren des aktuellen Objekts in einer Multithread-Anwendung verwendet werden, um kritische Abschnitte von Daten und Methoden zu schützen.

synchronized(this){
    // Do some thing. 
}

Anwendungsfall 3:

Die Implementierung des Builder- Musters hängt von der Verwendung von ab this, um das geänderte Objekt zurückzugeben.

Siehe diesen Beitrag

Builder in einer separaten Klasse halten (fließende Schnittstelle)

Ravindra Babu
quelle
2

Google hat auf der Sun-Website eine Seite aufgeschlagen, auf der dies ein wenig diskutiert wird.

Sie haben Recht mit der Variablen; thiskann in der Tat verwendet werden, um eine Methodenvariable von einem Klassenfeld zu unterscheiden.

    private int x;
    public void setX(int x) {
        this.x=x;
    }

Ich hasse diese Konvention jedoch wirklich . Zwei verschiedene Variablen mit buchstäblich identischen Namen zu versehen, ist ein Rezept für Fehler. Ich bevorzuge etwas in der Art von:

    private int x;
    public void setX(int newX) {
        x=newX;
    }

Gleiche Ergebnisse, aber ohne die Möglichkeit eines Fehlers, auf den Sie versehentlich verweisen, xwenn Sie eigentlich darauf verweisen xwollten.

Wenn Sie es mit einer Methode verwenden, haben Sie Recht mit den Effekten. Sie erhalten die gleichen Ergebnisse mit oder ohne. Kannst du es benutzen? Sicher. Solltest du es benutzen? Bis zu Ihnen, aber da ich persönlich denke, dass es sinnlose Ausführlichkeit ist, die keine Klarheit schafft (es sei denn, der Code ist voll mit statischen Importanweisungen), bin ich nicht geneigt, ihn selbst zu verwenden.

BlairHippo
quelle
4
Es ist keine Konvention, es ist ein Programmiersprachenmechanismus. Was Sie aufgelistet haben - mit newX (ich bevorzuge pX für Parameter x) ist eine Konvention.
Bill K
@ Bill K: Ich verstehe den Unterschied, den Sie machen, nicht. Ich kann wählen, ob ich die Eingabevariable x oder newX oder pX oder mangroveThroatWarblerX benennen möchte. Wie kann man ihm einen Namen geben, der mit der Variablen identisch ist, für die keine Konvention festgelegt wird, während "neue" oder "p" oder "kostenlose Monty Python-Referenzen" Konventionen vorangestellt werden?
BlairHippo
3
"Gratuitoud Monty Python References" ist keine Konvention, sondern das GESETZ.
Adam Robinson
+1: Aus diesem Grund verwenden wir für Argumente und Methodenvariablen einen anderen Namensstandard als für Klassenvariablen. Wir kürzen Argumente / Methodenvariablen ab und verwenden vollständige Wörter für Klassen- / Instanzvariablen.
Lawrence Dol
1
Das Lösen mithilfe einer Namenskonvention ist eine Konvention. Lösen mit einer Sprachfunktion - Ich denke, es wäre eine Konvention, diese Sprachfunktion niemals oder immer zu verwenden. Für jedes Mal, wenn Sie auf ein Mitglied zugreifen, ist dies eine Konvention. Ich denke, es ist nicht wichtig, ich hasse das auch.
Bill K
2

Im Folgenden finden Sie die Möglichkeiten, das Schlüsselwort 'this' in Java zu verwenden:

  1. Verwenden des thisSchlüsselworts zum Verweisen auf aktuelle Klasseninstanzvariablen
  2. Verwenden Sie this(), um den aktuellen Klassenkonstruktor aufzurufen
  3. Verwenden des thisSchlüsselworts zum Zurückgeben der aktuellen Klasseninstanz
  4. Verwendung thisStichwort als Methodenparameter

https://docs.oracle.com/javase/tutorial/java/javaOO/thiskey.html

Roottraveller
quelle
1

Wenn es zwei Variablen gibt, eine Instanzvariable und eine andere lokale Variable mit demselben Namen, verwenden wir diese. um auf das aktuell ausgeführte Objekt zu verweisen, um den Konflikt zwischen den Namen zu vermeiden.

Giri
quelle
1

thisist eine Referenz auf das aktuelle Objekt. Es wird im Konstruktor verwendet, um zwischen der lokalen und der aktuellen Klassenvariablen mit demselben Namen zu unterscheiden. z.B:

public class circle {
    int x;
    circle(int x){
        this.x =x;
        //class variable =local variable 
    }
} 

thiskann auch verwendet werden, um einen Konstruktor von einem anderen Konstruktor aufzurufen. z.B:

public class circle {
    int x;

    circle() { 
        this(1);
    }

    circle(int x) {
        this.x = x; 
    }
}
nouman shah
quelle
0

Wird es einen Unterschied geben, wenn ich in einigen Methoden "x" anstelle von "this.x" verwende?

Normalerweise nicht. Aber manchmal macht es einen Unterschied:

  class A {
     private int i;
     public A(int i) {
        this.i = i; // this.i can be used to disambiguate the i being referred to
     }
  }

Wenn ich nur "method ()" verwende, wird es nicht standardmäßig auf das aktuelle Objekt angewendet?

Ja. Verdeutlicht jedoch bei Bedarf, this.method()dass der Aufruf von diesem Objekt erfolgt.

amit
quelle
0

thishat keinen Einfluss auf den resultierenden Code - es handelt sich um den Operator für die Kompilierungszeit, und der mit oder ohne Code generierte Code ist derselbe. Wann Sie es verwenden müssen, hängt vom Kontext ab. Zum Beispiel müssen Sie es verwenden, wie Sie sagten, wenn Sie eine lokale Variable haben, die die Klassenvariable beschattet, und Sie möchten auf die Klassenvariable und nicht auf die lokale Variable verweisen.

edit: mit "resultierender Code ist der gleiche" meine ich natürlich, wenn eine Variable im lokalen Bereich die zur Klasse gehörende nicht verbirgt. So

class POJO {
   protected int i;

   public void modify() {
      i = 9;
   }

   public void thisModify() {
      this.i = 9;
   }
}

Der resultierende Code beider Methoden ist der gleiche. Der Unterschied besteht darin, dass eine Methode eine lokale Variable mit demselben Namen deklariert

  public void m() {
      int i;
      i = 9;  // i refers to variable in method's scope
      this.i = 9; // i refers to class variable
  }
doc
quelle
0

In Bezug auf William Brendels Beiträge und Fragen zu den Konferenzen in Bezug auf Fall 2 . Hier ist ein Beispiel:

public class Window {

  private Window parent;

  public Window (Window parent) {
    this.parent = parent;
  }

  public void addSubWindow() {
    Window child = new Window(this);
    list.add(child);
  }

  public void printInfo() {
    if (parent == null) {
      System.out.println("root");
    } else {
      System.out.println("child");
    }
  }

}

Ich habe gesehen, dass dies verwendet wird, wenn Eltern-Kind-Beziehungen mit Objekten erstellt werden. Bitte beachten Sie jedoch, dass es der Kürze halber vereinfacht ist.

Alija
quelle
0

Das Schlüsselwort "This" in Java wird verwendet, um auf aktuelle Klassenobjekte zu verweisen.

Es gibt 6 Verwendungen von "diesem" Schlüsselwort in Java

  1. Zugriff auf Variablen auf Klassenebene : Wird meistens verwendet, wenn die Variable auf lokaler und Klassenebene identisch ist
  2. Zugriff auf Klassenmethoden : Dies ist das Standardverhalten und kann ignoriert werden
  3. Zum Aufrufen eines anderen Konstruktors derselben Klasse
  4. Verwenden Sie das Schlüsselwort 'this' als Rückgabewert : zum Zurückgeben der aktuellen Instanz von der Methode
  5. Übergeben des Schlüsselworts 'this' als Argument an die Methode Übergeben: Zum Übergeben der aktuellen Klasseninstanz als Argument
  6. Dieses Schlüsselwort als Argument an den Konstruktor : Zum Übergeben der aktuellen Klasseninstanz als Argument

ref: https://stacktraceguru.com/java/this-keyword-in-java

Rupesh Agrawal
quelle
-8

Um sicherzustellen, dass die Mitglieder des aktuellen Objekts verwendet werden. In Fällen, in denen die Thread-Sicherheit ein Problem darstellt, können einige Anwendungen die falschen Objektelementwerte ändern. Aus diesem Grund sollte dies auf das Element angewendet werden, damit der richtige Objektelementwert verwendet wird.

Wenn sich Ihr Objekt nicht mit der Thread-Sicherheit befasst, gibt es keinen Grund, anzugeben, welcher Wert des Objektmitglieds verwendet wird.

Myster Oktober
quelle
Das ist wirklich nicht der Fall. Ich bin mir nicht einmal sicher, an welchen Fall Sie denken, aber ein Beispiel könnte hilfreich sein, um zu verstehen, was Sie sagen wollen.
David Berger
1
Ja. Ich weiß, was Sie erklären, betrifft die Thread-Sicherheit. Es gibt keine richtige Antwort auf diese Frage, die die Gewindesicherheit betrifft. Wenn "dies" erforderlich ist, um auf das richtige Objekt zu verweisen, ist die Methode oder das Attribut nur dann threadsicher, wenn sie synchronisiert ist. Wenn die Referenz überhaupt nicht eindeutig ist, ist es nicht eindeutig, ob Multithreading ein Problem darstellt oder nicht.
David Berger