Quando dovrei usare "questo" in una classe?


269

So che si thisriferisce a un oggetto corrente. Ma non so quando ho davvero bisogno di usarlo. Ad esempio, ci sarà qualche differenza se uso xinvece di this.xalcuni dei metodi? Potrebbe essere xriferito a una variabile che è locale per il metodo considerato? Intendo variabile che si vede solo in questo metodo.

Che dire this.method()? Posso usarlo? Dovrei usarlo. Se lo utilizzo method(), non verrà applicato per impostazione predefinita all'oggetto corrente?

Risposte:


349

La thisparola chiave viene utilizzata principalmente in tre situazioni. Il primo e più comune è nei metodi setter per chiarire i riferimenti alle variabili. Il secondo è quando è necessario passare l'istanza di classe corrente come argomento a un metodo di un altro oggetto. Il terzo è un modo per chiamare costruttori alternativi all'interno di un costruttore.

Caso 1: utilizzo thisper chiarire i riferimenti alle variabili. Nei metodi setter Java, comunemente passiamo in un argomento con lo stesso nome della variabile membro privata che stiamo tentando di impostare. Quindi assegniamo l'argomento xa this.x. Ciò chiarisce che si sta assegnando il valore del parametro "nome" alla variabile di istanza "nome".

public class Foo
{
    private String name;

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

Caso 2: utilizzo thiscome argomento passato a un altro oggetto.

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();
    }
}

Caso 3: utilizzo thisper chiamare costruttori alternativi. Nei commenti, la trinite indicava correttamente un altro uso comune di this. Quando si hanno più costruttori per una singola classe, è possibile utilizzare this(arg0, arg1, ...)per chiamare un altro costruttore di propria scelta, purché lo si faccia nella prima riga del costruttore.

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

        //optional other lines
    }

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

Ho anche visto thisusato per enfatizzare il fatto che si fa riferimento a una variabile di istanza (senza la necessità di chiarire le ambiguità), ma questo è un caso raro secondo me.


21
+1 Per menzionare che puoi anche passare questo come argomento. questo non è usato solo per chiarire le ambizioni.
Alex Jasmin,

12
Naturalmente c'è anche this(arg1, arg2, ...)dentro un costruttore.
Thomas Eding,

12
@Hazior: tendo a scrivere una risposta breve e ad aggiungerla nel tempo. A volte ciò si sovrappone alle risposte degli altri, a volte no. Nel caso della mia ultima modifica, trinithis ha sottolineato un altro uso comune di thisquello che ho dimenticato, quindi l'ho aggiunto alla mia risposta. Non vedo nulla di sbagliato in questo perché il risultato finale è una risposta complessivamente migliore, che è precisamente lo scopo di SO. Cerco anche di dare credito ove possibile, come ho fatto nel caso della trinite.
William Brendel,

4
Hai esempi per i casi 1 e 3. Puoi fornire un esempio del caso 2 in cui l'istanza della classe corrente viene utilizzata come argomento per un metodo di un'altra classe?
dbconfession,

4
@AStar Nella maggior parte delle basi di codice Java con cui ho lavorato nel corso degli anni, thisviene utilizzato solo se la disambiguazione è veramente necessaria, come nell'esempio del mio setter sopra. Gli stili di codifica e le "migliori pratiche" possono variare ampiamente a seconda di chi chiedi, ovviamente, ma in generale, raccomando di scegliere modelli ragionevoli e attenersi ad essi. La coerenza, anche solo all'interno di una singola base di codice, fa molta strada verso la leggibilità e la manutenibilità.
William Brendel,

71

Il secondo uso importante di this(oltre a nascondersi con una variabile locale come già dicono molte risposte) è quando si accede a un'istanza esterna da una classe non statica nidificata:

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;
    }
  }
}

46

Devi solo usarlo this- e la maggior parte delle persone lo usa solo - quando c'è una variabile locale sovrapposta con lo stesso nome. (Metodi setter, per esempio.)

Naturalmente, un'altra buona ragione da usare thisè che fa apparire intellisense negli IDE :)


1
Ma poi devi tornare indietro dopo averlo cercato. La programmazione è stancante!
LegendLength

25

L'unica necessità di utilizzare il this.qualificatore è quando un'altra variabile nell'ambito corrente condivide lo stesso nome e si desidera fare riferimento al membro dell'istanza (come descritto da William). A parte questo, non c'è differenza nel comportamento tra xe this.x.


3
E se hai nomi duplicati, una delle tue variabili dovrebbe essere rinominata in quanto è quasi sicuramente nominata in modo improprio. O almeno, potrebbe essere nominato meglio.
CaffGeek

3
@Chad: è pratica comune nei metodi setter Java. Tuttavia, al di fuori dei metodi setter, le tue affermazioni generalmente valgono.
William Brendel,

2
Potresti voler usare this.xper rendere il tuo codice un po 'più chiaro anche, anche la manutenibilità / leggibilità del codice è un fattore che dovresti considerare ...
Bryan Rehbein

1
@Chad: non posso essere abbastanza d'accordo con entusiasmo. Buon Dio, solo perché "questo". ti consente di assegnare a due variabili diverse lo stesso nome, perché VUOI?
BlairHippo

2
@Blair: Leggere la tua risposta chiarisce che non preferisci questa pratica nei metodi setter, ma molte persone lo fanno (includerei me stesso in quella lista). Se ho un metodo setter che accetta un valore, chiaramente il valore trasmesso deve essere il "nuovo" valore, quindi l'aggiunta di "nuovo" al nome della variabile sembra aggiungere inutili ridondanze all'API pubblica.
Adam Robinson,

15

"this" è utile anche quando si chiama un costruttore da un altro:

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

11

this è utile nel modello del generatore.

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();
    }

}

1
Questo era il tipo di risposta che volevo quando ho cercato e finito qui, ma non hai spiegazioni sul tuo codice, quindi la maggior parte delle persone che chiedono "questo", non capiranno cosa "restituisce un nuovo utente (questo);" significa, come io non ...
nckbrz,

Il modello Builder viene utilizzato per specificare chiaramente i parametri sulla costruzione. Invece di avere un nuovo utente (stringa, stringa) senza un modo semplice per dire quale stringa fosse quale, avresti un nuovo Builder (). SetFirstName ("Jane"). SetSurname ("Smith"). Build (). Si restituisce questo dalle funzioni Builder.set ... () in modo da poterli concatenare.
ChrisPhoenix,

10

Ci sono molte buone risposte, ma c'è un'altra ragione molto piccola da mettere thisovunque. Se hai provato ad aprire i tuoi codici sorgente da un normale editor di testo (ad esempio blocco note, ecc.), L'utilizzo thisrenderà molto più chiaro da leggere.

Immagina questo:

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;
        }
    }
}

Questo è molto chiaro da leggere con qualsiasi IDE moderno, ma sarà un incubo da leggere con un normale editor di testo.

Farai fatica a scoprire dove foorisiede, finché non usi la funzione "trova" dell'editor. Allora urlerai getStringFromSomewhere()per lo stesso motivo. Infine, dopo aver dimenticato ciò che sè, questo bar = sti darà il colpo finale.

Confrontalo con questo:

public void doSomething() {
    // More codes
    Hello.this.foo = "FOO";
    // More codes
    String s = Hello.this.getStringFromSomewhere();
    // More codes
    this.bar = s;
}
  1. Sai fooè una variabile dichiarata nella classe esterna Hello.
  2. Sai getStringFromSomewhere()è un metodo dichiarato anche nella classe esterna.
  3. Sai che barappartiene alla Worldclasse ed sè una variabile locale dichiarata in quel metodo.

Ovviamente, ogni volta che progetti qualcosa, crei regole. Così, mentre la progettazione del API o progetto, se le regole sono "se qualcuno apre tutti questi codici sorgente con un blocco note, lui o lei dovrebbe sparargli / se stessa in testa", allora siete totalmente bene non fare questo .


ottima risposta @Jai
gaurav,

Il primo motivo per sparare sarebbe scrivere classi con più di 10k righe di codice, specialmente se il codice è già suddiviso in classi diverse che non hanno bisogno di essere annidate :)
LuCio,

@LuCio Lol true xD
Jai,

7

A meno che tu non abbia nomi di variabili sovrapposti, è davvero solo per chiarezza quando leggi il codice.


1
Quando vedi costantemente la thisparola chiave quando non è necessaria, è solo il codice del bollettino che rende il codice più difficile da leggere.
AxeEffect,

Mi sono appena imbattuto in un progetto open source che richiede a tutti i membri il prefisso "this". A parte questo, il progetto è ben scritto ma sono tentato di entrare in un dibattito religioso con loro.
LegendLength

4
@AxeEffect So che questo è davvero vecchio ma ... thisNON rende il codice più difficile da leggere lmao.
Xatenev,

4

La risposta di @William Brendel ha fornito tre diversi casi d'uso in modo piacevole.

Caso d'uso 1:

La pagina di documentazione Java ufficiale su questo fornisce gli stessi casi d'uso.

All'interno di un metodo di istanza o di un costruttore, si tratta di un riferimento all'oggetto corrente, l'oggetto di cui viene chiamato il metodo o il costruttore. È possibile fare riferimento a qualsiasi membro dell'oggetto corrente dall'interno di un metodo di istanza o di un costruttore usando questo.

Comprende due esempi:

Usando questo con un campo e usando questo con un costruttore

Caso d'uso 2:

Altro caso d'uso che non è stato citato in questo post: thispuò essere utilizzato per sincronizzare l'oggetto corrente in un'applicazione multi-thread per proteggere la sezione critica di dati e metodi.

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

Caso d'uso 3:

L'implementazione del modello Builder dipende dall'uso di thisper restituire l'oggetto modificato.

Fare riferimento a questo post

Mantenere il costruttore in una classe separata (interfaccia fluida)


2

Google ha aperto una pagina sul sito Sun che ne discute un po '.

Hai ragione sulla variabile; thispuò infatti essere utilizzato per differenziare una variabile di metodo da un campo di classe.

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

Tuttavia, odio davvero quella convenzione. Dare due variabili diverse nomi letteralmente identici è una ricetta per i bug. Preferisco di gran lunga qualcosa sulla falsariga di:

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

Stessi risultati, ma senza alcuna possibilità di un bug a cui ti riferisci accidentalmente xquando invece intendevi davvero fare riferimento a x.

Per quanto riguarda l'utilizzo con un metodo, hai ragione sugli effetti; otterrai gli stessi risultati con o senza di essa. Puoi usarlo? Sicuro. Dovresti usarlo? Spetta a te, ma dato che penso personalmente che sia la verbosità inutile che non aggiunge alcuna chiarezza (a meno che il codice non sia pieno zeppo di dichiarazioni statiche di importazione), non sono propenso a usarlo da solo.


4
Non è una convenzione, è un meccanismo di scoping del linguaggio di programma. Quello che hai elencato: usare newX (preferisco pX per il parametro x) è una convenzione.
Bill K

@ Bill K: Non capisco la distinzione che stai facendo. Posso scegliere di nominare la variabile di input x, o newX, o pX o mangroveThroatWarblerX. In che modo la scelta di assegnargli un nome identico alla variabile NON imposta una convenzione, mentre si antepongono le convenzioni "new" o "p" o "Gratuitous Monty Python References"?
BlairHippo

3
"Gratuitoud Monty Python References" non è una convenzione, è la LEGGE.
Adam Robinson,

+1: per questo motivo utilizziamo uno standard di denominazione diverso per argomenti e variabili di metodo rispetto a quello delle variabili di classe. Abbreviamo argomenti / metodi var e usiamo parole complete per variabili di classe / istanza.
Lawrence Dol

1
Risolvere usando una convenzione di denominazione è, hmm, una convenzione. Risolverlo usando una funzione della lingua - Immagino che scegliere di non usare mai quella funzione della lingua o di usarla sempre sarebbe una convenzione ... Usare questa. per ogni volta che accedi a un membro sarebbe una convenzione. Immagino che non abbia molta importanza, odio anche questo.
Bill K

2

Di seguito sono riportati i modi per utilizzare la parola chiave 'this' in java:

  1. Utilizzo della thisparola chiave per fare riferimento alle variabili di istanza della classe corrente
  2. Utilizzo this()per invocare il costruttore della classe corrente
  3. Utilizzo della thisparola chiave per restituire l'istanza della classe corrente
  4. Utilizzo della thisparola chiave come parametro del metodo

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


1

quando ci sono due variabili una variabile di istanza e l'altra variabile locale con lo stesso nome, allora usiamo questo. per fare riferimento all'oggetto corrente in esecuzione per evitare il conflitto tra i nomi.


1

thisè un riferimento all'oggetto corrente. Viene utilizzato nel costruttore per distinguere tra la variabile di classe locale e quella corrente che hanno lo stesso nome. per esempio:

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

thispuò anche essere usato per chiamare un costruttore da un altro costruttore. per esempio:

public class circle {
    int x;

    circle() { 
        this(1);
    }

    circle(int x) {
        this.x = x; 
    }
}

0

Ci sarà qualche differenza se uso "x" invece di "this.x" in alcuni dei metodi?

Di solito no. Ma a volte fa la differenza:

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

Se utilizzo semplicemente "method ()", non verrà applicato, per impostazione predefinita, all'oggetto corrente?

Sì. Ma se necessario, this.method()chiarisce che la chiamata viene effettuata da questo oggetto.


0

thisnon influisce sul codice risultante: è l'operatore del tempo di compilazione e il codice generato con o senza sarà lo stesso. Quando devi usarlo, dipende dal contesto. Ad esempio, devi usarlo, come hai detto, quando hai una variabile locale che ombreggia la variabile di classe e vuoi fare riferimento alla variabile di classe e non a una locale.

modifica: per "il codice risultante sarà lo stesso" intendo ovviamente, quando alcune variabili nell'ambito locale non nascondono quella appartenente alla classe. così

class POJO {
   protected int i;

   public void modify() {
      i = 9;
   }

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

il codice risultante di entrambi i metodi sarà lo stesso. La differenza sarà se un metodo dichiara una variabile locale con lo stesso nome

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

0

Rispetto ai post di William Brendel e alla domanda dbconfessions , relativa al caso 2 . Ecco un esempio:

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");
    }
  }

}

Ho visto questo usato, quando si costruiscono relazioni genitore-figlio con oggetti. Tuttavia, si ricorda che è semplificato per brevità.


0

La parola chiave "this" in java viene utilizzata per fare riferimento agli oggetti di classe correnti.

Ci sono 6 usi della parola chiave "this" in java

  1. Accesso alla variabile di livello classe : usata principalmente se la variabile locale e di classe è uguale
  2. Accesso ai metodi di classe : questo è un comportamento predefinito e può essere ignorato
  3. Per aver chiamato un altro costruttore della stessa classe
  4. Utilizzo della parola chiave "this" come valore di ritorno : per restituire l'istanza corrente dal metodo
  5. Passando la parola chiave "this" come argomento al metodo Passing: per passare l'istanza di classe corrente come argomento
  6. questa parola chiave come argomento al costruttore : per passare l'istanza di classe corrente come argomento

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


-8

Per assicurarsi che vengano utilizzati i membri dell'oggetto corrente. Casi in cui la sicurezza del thread è un problema, alcune applicazioni potrebbero modificare i valori dei membri degli oggetti errati, per questo motivo questo dovrebbe essere applicato al membro in modo che venga utilizzato il valore del membro oggetto corretto.

Se il tuo oggetto non è interessato alla sicurezza del thread, non c'è motivo di specificare quale valore del membro oggetto viene utilizzato.


Questo non è davvero il caso. Non sono nemmeno sicuro di quale caso stai pensando, ma un esempio potrebbe essere utile per capire cosa stai cercando di dire.
David Berger,

1
Sì. So che cosa stai spiegando riguarda la sicurezza del thread. Non esiste una risposta corretta a questa domanda che implica la sicurezza del thread. Se "this" è necessario per fare riferimento all'oggetto corretto, quindi una volta che lo fa, il metodo o l'attributo saranno thread-safe se e solo se è sincronizzato. Se il riferimento è per nulla ambiguo, sarà ambiguo se il multi-threading sia o meno un problema.
David Berger,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.