Kiedy powinienem używać „tego” na zajęciach?

267

Wiem, że thisodnosi się to do bieżącego obiektu. Ale nie wiem, kiedy naprawdę muszę go użyć. Na przykład, czy będzie jakaś różnica, jeśli użyję xzamiast this.xniektórych metod? Może xbędzie dotyczyć zmiennej lokalnej dla rozważanej metody? Mam na myśli zmienną, która jest widoczna tylko w tej metodzie.

Co this.method()? Mogę to użyć? Czy powinienem go użyć. Jeśli po prostu użyję method(), czy domyślnie nie zostanie zastosowane do bieżącego obiektu?

rzymski
źródło

Odpowiedzi:

347

Słowo thiskluczowe jest używane przede wszystkim w trzech sytuacjach. Pierwszą i najczęstszą jest metoda ustawiania w celu ujednoznacznienia odniesień zmiennych. Drugim jest, gdy istnieje potrzeba przekazania bieżącej instancji klasy jako argumentu do metody innego obiektu. Trzeci to sposób na wywołanie alternatywnych konstruktorów z poziomu konstruktora.

Przypadek 1: Użycie thisdo ujednoznacznienia odniesień zmiennych. W metodach ustawiających Java zwykle przekazujemy argument o tej samej nazwie co zmienna prywatnego członka, którą próbujemy ustawić. Następnie przypisujemy argument xdo this.x. To wyjaśnia, że ​​przypisujesz wartość parametru „name” do zmiennej instancji „name”.

public class Foo
{
    private String name;

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

Przypadek 2: Użycie thisjako argumentu przekazanego do innego obiektu.

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

Przypadek 3: Używanie thisdo wywoływania alternatywnych konstruktorów. W komentarzach Trinithis poprawnie wskazał na inne powszechne zastosowanie this. Jeśli masz wiele konstruktorów dla jednej klasy, możesz użyć this(arg0, arg1, ...)wywołania innego wybranego konstruktora, pod warunkiem, że zrobisz to w pierwszym wierszu swojego konstruktora.

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

        //optional other lines
    }

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

Zauważyłem również this, że podkreślałem fakt, że odwołuje się do zmiennej instancji (bez potrzeby ujednoznacznienia), ale moim zdaniem jest to rzadki przypadek.

William Brendel
źródło
21
+1 Za wzmiankę, że możesz również przekazać to jako argument. ten nie jest używany tylko do zakresu dezambiguacji.
Alex Jasmin
12
Oczywiście jest też this(arg1, arg2, ...)wewnątrz konstruktora.
Thomas Eding,
12
@Hazior: Zwykle piszę krótką odpowiedź, a potem z czasem ją uzupełniam. Czasami pokrywa się to z odpowiedziami innych ludzi, czasem nie. W przypadku mojej ostatniej edycji Trinithis wskazał inne popularne zastosowanie, o thisktórym zapomniałem, więc dodałem je do mojej odpowiedzi. Nie widzę w tym nic złego, ponieważ wynik końcowy jest lepszą odpowiedzią, co jest dokładnie celem SO. Staram się również dawać uznanie tam, gdzie to możliwe, tak jak w przypadku Trinithis.
William Brendel,
4
Masz przykłady dla przypadku 1 i 3. Czy możesz podać przykład przypadku 2, w którym bieżąca instancja klasy jest używana jako argument dla metody innej klasy?
dbconfession
4
@AStar W większości baz kodu Java, z którymi pracowałem przez lata, thisjest używany tylko wtedy, gdy naprawdę konieczne jest ujednoznacznienie, jak w moim poprzednim przykładzie. Style kodowania i „najlepsze praktyki” mogą się znacznie różnić w zależności od tego, kogo zapytasz, ale ogólnie rzecz biorąc, zalecam wybór rozsądnych wzorów i trzymanie się ich. Spójność, nawet tylko wewnętrznie w ramach jednej bazy kodu, znacznie przyczynia się do czytelności i konserwacji.
William Brendel
71

Drugim ważnym zastosowaniem this(oprócz ukrywania za pomocą zmiennej lokalnej, jak już wiele odpowiedzi już mówi) jest dostęp do zewnętrznej instancji z zagnieżdżonej klasy niestatycznej:

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
źródło
46

Musisz użyć this- i większość ludzi korzysta z niego - tylko wtedy, gdy zachodzi na siebie zmienna lokalna o tej samej nazwie. (Na przykład metody Settera.)

Oczywiście innym dobrym powodem do użycia thisjest to, że powoduje wyskakiwanie inteligencji w IDE :)

froadie
źródło
1
Ale potem musisz to cofnąć po sprawdzeniu. Programowanie jest męczące!
LegendLength,
25

Jedynym potrzeba użyć this.kwalifikator jest, gdy inny zmienna w obecnych udziałów zakres tej samej nazwie i chcesz zapoznać się z członka instancji (podobnie jak William opisuje). Poza tym nie ma różnicy w zachowaniu między xi this.x.

Adam Robinson
źródło
3
A jeśli masz zduplikowane nazwy, jedna ze zmiennych powinna zostać zmieniona, ponieważ prawie na pewno jest niepoprawnie nazwana. A przynajmniej można go nazwać lepiej.
CaffGeek
3
@Chad: Jest to powszechna praktyka w metodach ustawiania Java. Jednak poza metodami settera, twoje stwierdzenia na ogół się zachowują.
William Brendel,
2
Możesz także użyć, this.xaby twój kod był czytany nieco jaśniej, łatwość konserwacji / czytelność kodu jest również czynnikiem, który powinieneś wziąć pod uwagę ...
Bryan Rehbein
1
@Chad: Nie mogę się wystarczająco entuzjastycznie zgodzić. Dobry Boże, tylko dlatego, że „to”. pozwala ci nadać dwie różne zmienne tę samą nazwę, dlaczego miałbyś tego chcieć?
BlairHippo
2
@Blair: Przeczytanie twojej odpowiedzi jasno pokazuje, że nie preferujesz tej praktyki w metodach seterów, ale robi to wiele osób (chciałbym umieścić siebie na tej liście). Jeśli mam metodę ustawiającą, która przyjmuje wartość, to oczywiście przekazana wartość ma być „nową” wartością, więc dodanie „nowej” do nazwy zmiennej wydaje się dodawać niepotrzebną redundancję do publicznego API.
Adam Robinson,
15

„to” jest również przydatne, gdy wywołuje się jednego konstruktora od drugiego:

public class MyClass {
    public MyClass(String foo) {
        this(foo, null);
    }
    public MyClass(String foo, String bar) {
        ...
    }
}
Benzoes
źródło
11

this jest użyteczny we wzorze konstruktora.

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
źródło
1
To był rodzaj odpowiedzi, której chciałem, kiedy szukałem i skończyłem tutaj, ale nie masz wyjaśnienia swojego kodu, więc większość osób, które pytają o „to”, nie zrozumie, co „zwróci nowy użytkownik (ten);” oznacza, jak ja nie ...
nckbrz
Wzorzec konstruktora służy do wyraźnego określenia parametrów konstrukcji. Zamiast mieć nowego użytkownika (ciąg, ciąg) bez łatwego sposobu na określenie, który ciąg jest, który miałbyś, miałbyś nowego Buildera (). SetFirstName („Jane”). SetSename („Smith”). Build (). Zwracasz to z funkcji Builder.set ... (), aby móc je połączyć.
ChrisPhoenix,
10

Istnieje wiele dobrych odpowiedzi, ale istnieje jeszcze jeden bardzo niewielki powód, aby umieścić thiswszędzie. Jeśli próbujesz otworzyć kody źródłowe z normalnego edytora tekstu (np. Notatnika itp.), Użycie thissprawi, że czytanie będzie znacznie łatwiejsze.

Wyobraź to sobie:

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

Jest to bardzo jasne do odczytania za pomocą dowolnego nowoczesnego IDE, ale będzie to całkowity koszmar do przeczytania za pomocą zwykłego edytora tekstu.

Będziesz się starał dowiedzieć się, gdzie foomieszka, dopóki nie użyjesz funkcji „znajdź” edytora. Wtedy będziesz krzyczeć getStringFromSomewhere()z tego samego powodu. Wreszcie, kiedy zapomnisz, co sjest, bar = sda ci to ostateczny cios.

Porównaj to z tym:

public void doSomething() {
    // More codes
    Hello.this.foo = "FOO";
    // More codes
    String s = Hello.this.getStringFromSomewhere();
    // More codes
    this.bar = s;
}
  1. Wiesz, foojest to zmienna zadeklarowana w klasie zewnętrznej Hello.
  2. Wiesz, że getStringFromSomewhere()jest to metoda zadeklarowana również w klasie zewnętrznej.
  3. Wiesz, że barnależy do Worldklasy i sjest lokalną zmienną zadeklarowaną w tej metodzie.

Oczywiście za każdym razem, gdy coś projektujesz, tworzysz reguły. Jeśli więc projektujesz interfejs API lub projekt, jeśli Twoje zasady obejmują: „jeśli ktoś otworzy wszystkie te kody źródłowe za pomocą notatnika, powinien postrzelić się w głowę”, to jest całkowicie w porządku, aby tego nie robić .

Jai
źródło
świetna odpowiedź @Jai
gaurav
Pierwszym powodem do zrobienia zdjęcia byłoby napisanie zajęć z kilkoma 10 000 liniami kodu, szczególnie jeśli kod jest już podzielony na różne klasy, które nie muszą być zagnieżdżane :)
LuCio,
@LuCio Lol true xD
Jai
7

Chyba, że ​​masz nakładające się nazwy zmiennych, to naprawdę tylko dla przejrzystości podczas czytania kodu.

ChickenMilkBomb
źródło
1
Kiedy stale widzisz thissłowo kluczowe, gdy nie jest to konieczne, jest to po prostu kod, który utrudnia odczytanie kodu.
AxeEffect,
Właśnie natknąłem się na projekt open source, który wymaga, aby wszyscy członkowie mieli przedrostek „to”. Poza tym projekt jest bardzo dobrze napisany, ale kusi mnie, aby rozpocząć z nimi religijną debatę.
LegendLength,
4
@AxeEffect Wiem, że to jest naprawdę stary, ale ... thisNIE sprawia, że ​​kod trudniej odczytać lmao.
Xatenev
4

@William Brendel w odpowiedzi podał trzy różne przypadki użycia w przyjemny sposób.

Przypadek użycia 1:

Oficjalna strona dokumentacji Java na tej stronie zawiera te same przypadki użycia.

W ramach metody instancji lub konstruktora jest to odwołanie do bieżącego obiektu - obiektu, którego metoda lub konstruktor jest wywoływany. Za pomocą tego można odwoływać się do dowolnego elementu bieżącego obiektu z poziomu metody instancji lub konstruktora.

Obejmuje dwa przykłady:

Używanie tego z polem i Używanie tego z konstruktorem

Przypadek użycia 2:

Inny przypadek użycia, który nie został zacytowany w tym poście: thismożna go użyć do synchronizacji bieżącego obiektu w aplikacji wielowątkowej w celu ochrony krytycznej sekcji danych i metod.

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

Przypadek użycia 3:

Implementacja wzorca Konstruktora zależy od użycia thisdo zwrócenia zmodyfikowanego obiektu.

Zobacz ten post

Utrzymywanie konstruktora w osobnej klasie (płynny interfejs)

Ravindra babu
źródło
2

Google wyświetliło stronę w witrynie Sun, która nieco to omawia.

Masz rację co do zmiennej; thismożna rzeczywiście zastosować do odróżnienia zmiennej metody od pola klasy.

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

Jednak naprawdę nie znoszę tej konwencji. Podanie dwóch różnych zmiennych dosłownie identycznych nazw to przepis na błędy. Wolę coś w stylu:

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

Te same wyniki, ale bez szansy na błąd, do którego przypadkowo się odwołujesz, xkiedy tak naprawdę chciałeś to zrobić x.

Jeśli chodzi o korzystanie z metody, masz rację co do efektów; uzyskasz takie same wyniki z nim lub bez niego. Czy możesz tego użyć? Pewnie. Czy powinieneś go użyć? Od ciebie, ale biorąc pod uwagę, że osobiście uważam, że to bezcelowa gadatliwość nie dodaje żadnej przejrzystości (chyba że kod jest wypełniony statycznymi instrukcjami importu), nie jestem skłonny do używania go sam.

BlairHippo
źródło
4
To nie jest konwencja, to mechanizm określania zakresu języka programu. To, co wymieniłeś - użycie newX (wolę pX dla parametru x) to konwencja.
Bill K
@ Bill K: Nie rozumiem tego, co czynisz. Mogę wybrać nazwę zmiennej wejściowej x, newX, pX lub mangroveThroatWarblerX. W jaki sposób decyduje się na nadanie mu nazwy identycznej ze zmienną, która NIE jest konwencją, przy jednoczesnym dodawaniu konwencji „nowe” lub „p” lub „Nieuzasadnione referencje Monty Python” SĄ Konwencje?
BlairHippo
3
„Gratuitoud Monty Python References” to nie konwencja, to LAW.
Adam Robinson,
+1: Z tego powodu używamy innego standardu nazewnictwa dla argumentów i zmiennych metod niż dla zmiennych klas. Skracamy argumenty / zmienne metod i używamy pełnych słów dla zmiennych klasy / instancji.
Lawrence Dol
1
Rozwiązanie go za pomocą konwencji nazewnictwa jest, hmm, konwencją. Rozwiązanie go za pomocą funkcji językowej - chyba nigdy nie będę używać tej funkcji językowej lub zawsze będzie to konwencja ... Korzystanie z tego. za każdym razem, gdy uzyskujesz dostęp do członka, byłaby konwencja. Chyba nie ma to większego znaczenia, nienawidzę również tego.
Bill K
2

Oto sposoby używania tego słowa kluczowego w java:

  1. Użycie thissłowa kluczowego do odwołania do bieżących zmiennych instancji klasy
  2. Użycie this()do wywołania bieżącego konstruktora klasy
  3. Użycie thissłowa kluczowego do zwrócenia bieżącej instancji klasy
  4. Użycie thissłowa kluczowego jako parametru metody

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

roottraveller
źródło
1

gdy są dwie zmienne, jedna zmienna instancji i inna zmienna lokalna o tej samej nazwie, wówczas używamy tej. odsyłanie do bieżącego obiektu wykonującego, aby uniknąć konfliktu między nazwami.

Giri
źródło
1

thisjest odniesieniem do bieżącego obiektu. Jest używany w konstruktorze do rozróżnienia lokalnej i bieżącej zmiennej klasy o tej samej nazwie. na przykład:

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

thismożna również użyć do wywołania jednego konstruktora z innego konstruktora. na przykład:

public class circle {
    int x;

    circle() { 
        this(1);
    }

    circle(int x) {
        this.x = x; 
    }
}
Nouman Shah
źródło
0

Czy będzie jakaś różnica, jeśli użyję „x” zamiast „this.x” w niektórych metodach?

Zwykle nie. Ale czasami robi to różnicę:

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

Jeśli po prostu użyję metody „method ()”, czy domyślnie nie zostanie zastosowana do bieżącego obiektu?

Tak. Ale w razie potrzeby this.method()wyjaśnia, że ​​wywołanie jest wykonywane przez ten obiekt.

amit
źródło
0

thisnie wpływa na wynikowy kod - jest operatorem czasu kompilacji, a kod wygenerowany z nim lub bez będzie taki sam. Kiedy musisz go użyć, zależy od kontekstu. Na przykład musisz go użyć, jak powiedziałeś, kiedy masz zmienną lokalną, która zaciemnia zmienną klasy i chcesz odwoływać się do zmiennej klasy, a nie lokalnej.

edit: przez „wynikowy kod będzie taki sam” Mam na myśli oczywiście, że jakaś zmienna w zasięgu lokalnym nie ukrywa zmiennej należącej do klasy. A zatem

class POJO {
   protected int i;

   public void modify() {
      i = 9;
   }

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

wynikowy kod obu metod będzie taki sam. Różnica polega na tym, że jakaś metoda deklaruje zmienną lokalną o tej samej nazwie

  public void m() {
      int i;
      i = 9;  // i refers to variable in method's scope
      this.i = 9; // i refers to class variable
  }
dok
źródło
0

W odniesieniu do postów Williama Brendela i pytania dbconfessions dotyczących przypadku 2 . Oto przykład:

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

}

Widziałem to używane podczas budowania relacji rodzic-dziecko z obiektami. Należy jednak pamiętać, że jest to uproszczone ze względu na zwięzłość.

Alija
źródło
0

„To” słowo kluczowe w java służy do odwoływania się do bieżących obiektów klasy.

Istnieje 6 zastosowań słowa kluczowego „this” w java

  1. Dostęp do zmiennej na poziomie klasy : najczęściej używany, jeśli zmienna lokalna i na poziomie klasy jest taka sama
  2. Dostęp do metod klasowych : jest to zachowanie domyślne i można je zignorować
  3. Do wywoływania innego konstruktora tej samej klasy
  4. Używanie słowa kluczowego „this” jako wartości zwracanej : do zwracania bieżącej instancji z metody
  5. Przekazywanie słowa kluczowego „this” jako argumentu do metody Passing: do przekazywania bieżącej instancji klasy jako argumentu
  6. to słowo kluczowe jako argument konstruktora : do przekazywania bieżącej instancji klasy jako argumentu

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

Rupesh Agrawal
źródło
-8

Aby upewnić się, że używane są elementy bieżącego obiektu. W przypadkach, w których bezpieczeństwo wątków stanowi problem, niektóre aplikacje mogą zmieniać niepoprawne wartości elementów składowych, dlatego należy to zastosować do elementu, aby użyć prawidłowej wartości elementu składowego.

Jeśli twój obiekt nie zajmuje się bezpieczeństwem wątków, nie ma powodu, aby określać, która wartość elementu obiektu jest używana.

Tajemniczy październik
źródło
Tak naprawdę tak nie jest. Nie jestem nawet pewien, o czym myślisz, ale przykład może być pomocny w zrozumieniu tego, co próbujesz powiedzieć.
David Berger,
1
Tak. Wiem, że to, co wyjaśniasz, obejmuje bezpieczeństwo wątków. Nie ma poprawnej odpowiedzi na to pytanie, która dotyczy bezpieczeństwa wątków. Jeśli „to” jest konieczne, aby odwołać się do właściwego obiektu, wówczas metoda lub atrybut będzie bezpieczny dla wątku tylko wtedy, gdy zostanie zsynchronizowany. Jeśli odwołanie jest w ogóle niejednoznaczne, będzie dwuznaczne, czy problemem jest wielowątkowość.
David Berger,