Коли я повинен використовувати "це" в класі?


267

Я знаю, що це thisстосується поточного об'єкта. Але я не знаю, коли мені справді потрібно це використовувати. Наприклад, чи буде якась різниця, якщо я використовую xзамість this.xдеяких методів? Може xпосилатися на змінну, яка є локальною для розглянутого методу? Я маю на увазі змінну, яка спостерігається лише в цьому методі.

Про що this.method()? Чи можу я його використовувати? Чи варто його використовувати. Якщо я просто використовую method(), чи не буде він за замовчуванням застосований до поточного об'єкта?

Відповіді:


347

thisКлючове слово використовується в основному в трьох ситуаціях. Перший і найпоширеніший - це методи сеттера для розмежування змінних посилань. Друга - це коли потрібно передати поточний екземпляр класу як аргумент методу іншого об’єкта. Третій - це спосіб викликати альтернативні конструктори всередині конструктора.

Випадок 1: Використання thisдля розмежування змінних посилань. У методах встановлення Java ми зазвичай передаємо аргумент з тим самим іменем, що і змінну приватного члена, яку ми намагаємося встановити. Потім призначаємо аргументx до this.x. Це дає зрозуміти, що ви присвоюєте значення параметра "name" змінної примірника "name".

public class Foo
{
    private String name;

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

Випадок 2: Використанняthis в якості аргументу передається іншому об'єкту.

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

Випадок 3: Використання thisдля виклику альтернативних конструкторів. У коментарях триніт правильно вказав на ще одне поширене використання this. Якщо у вас є кілька конструкторів для одного класу, ви можете використовуватиthis(arg0, arg1, ...) зателефонувати іншому конструктору за своїм вибором, якщо це зробити в першому рядку конструктора.

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

        //optional other lines
    }

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

Я також бачив, thisяк підкреслював той факт, що на посилання на змінну примірника посилається (це означає необхідність розбірливості), але, на мою думку, це рідкісний випадок.


21
+1 Зазначивши, що ви можете також передати це як аргумент. це використовується не лише для розрізнення діапазону.
Олексій Жасмін

12
Звичайно, є і this(arg1, arg2, ...)всередині конструктора.
Томас Едінг

12
@Hazior: Я схильний писати коротку відповідь, а потім додавати її до часу. Іноді це збігається з відповідями інших людей, іноді ні. Що стосується моєї останньої редакції, тринітис вказав на ще одне поширене використання, thisяке я забув, тому я додав це до своєї відповіді. Я не бачу в цьому нічого поганого, тому що кінцевий результат - це краща відповідь у цілому, саме в цьому і полягає мета ТА. Я також намагаюся дати кредит, коли це можливо, як це було у випадку тринітісу.
Вільям Брендель

4
У вас є приклади для випадків 1 і 3. Чи можете ви навести приклад випадку 2, коли поточний екземпляр класу використовується як аргумент для методу іншого класу?
dbconfession

4
@AStar У більшості баз кодів Java, з якими я працював протягом багатьох років, thisвикористовується лише в тому випадку, якщо розбірливість справді необхідна, як у моєму прикладі сеттера вище. Стилі кодування та "найкращі практики" можуть, в залежності від того, кого ви запитуєте, різниться, але загалом, я рекомендую вибирати розумні шаблони та дотримуватися їх. Послідовність, навіть лише всередині однієї бази даних, проходить довгий шлях до читабельності та ремонтопридатності.
Вільям Брендель,

71

Друге важливе використання this(крім приховування локальної змінної, скільки вже відповідей) - це доступ до зовнішнього екземпляра з вкладеного нестатичного класу:

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

Вам потрібно використовувати this- і більшість людей користується ним лише тоді, коли є локальна змінна, що перекривається, з такою ж назвою. (Наприклад, методи встановлення.)

Звичайно, ще одна вагома причина використання this- це те, що це викликає інтелігенцію, що з'являється в IDE :)


1
Але тоді вам доведеться повернути його назад після того, як ви подивитеся на нього. Програмування стомлює!
LegendLength

25

Єдиною потребою у використанні this.кваліфікатора є те, коли інша змінна в поточному діапазоні має те саме ім'я, і ​​ви хочете звернутися до члена екземпляра (як описує Вільям). Крім цього, між поведінкою xта між ними немає різниці в поведінці this.x.


3
І якщо у вас є дублюючі імена, одну із змінних слід перейменувати, оскільки вона майже напевно названа неправильно. Або, принаймні, можна назвати кращим.
CaffGeek

3
@Chad: Це звичайна практика в методах встановлення Java. Однак, за винятком методів встановлення, ваші твердження, як правило, справедливі.
Вільям Брендель

2
Ви можете скористатися this.xдля того, щоб ваш код читався трохи чіткіше, також є можливість збереження / читабельності коду - фактор, про який слід розглянути ...
Брайан Рехбін,

1
@Chad: Я не можу погодитися з ентузіазмом. Добрий Господи, тільки тому, що "це". дозволяє надати двом різним змінним однакове ім’я, чому б ви хотіли?
BlairHippo

2
@Blair: Читаючи вашу відповідь, стає зрозуміло, що ви не віддаєте перевагу цій практиці методам сеттера, але багато людей це роблять (я б включив себе до цього списку). Якщо у мене є метод встановлення, який приймає значення, очевидно, що передане значення має бути "новим" значенням, тому додавання "нового" до імені змінної, здається, додасть зайвого надмірності публічному API.
Адам Робінсон

15

"Це" також корисно для виклику одного конструктора від іншого:

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

11

this корисна за схемою для будівельників.

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
Цей тип відповіді я хотів, коли я шукав і опинився тут, але ви не маєте пояснення свого коду, тому більшість людей, які запитують про "це", не зрозуміють, що "повернути нового користувача (це);" означає, як я не ...
nckbrz

Шаблон Builder використовується для чіткого визначення параметрів конструкції. Замість того щоб мати нового Користувача (рядок, рядок), не маючи простого способу сказати, яка строка була, у вас з'явиться новий Builder (). SetFirstName ("Jane"). SetSurname ("Smith"). Build (). Ви повертаєте це з функцій Builder.set ... (), щоб ви могли їх ланцюжок.
ChrisPhoenix

10

Хороших відповідей є багато, але є ще одна дуже незначна причина thisскрізь. Якщо ви спробували відкрити свої вихідні коди у звичайному текстовому редакторі (наприклад, блокнот тощо), використання thisце зробить його набагато зрозумілішим для читання.

Уявіть собі це:

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

Це дуже зрозуміло для читання з будь-яким сучасним IDE, але це буде загальним кошмаром для читання із звичайним текстовим редактором.

Ви будете боротися, щоб дізнатись, де fooзнаходиться, поки не скористаєтесь функцією редактора «знайти». Тоді ви будете кричати на getStringFromSomewhere()ту ж причину. Нарешті, після того як ви забули, що sтаке, bar = sце завдасть вам остаточного удару.

Порівняйте це з цим:

public void doSomething() {
    // More codes
    Hello.this.foo = "FOO";
    // More codes
    String s = Hello.this.getStringFromSomewhere();
    // More codes
    this.bar = s;
}
  1. Ви знаєте foo, це змінна заявлена ​​у зовнішньому класі Hello.
  2. Ви знаєте getStringFromSomewhere(), це метод, оголошений і в зовнішньому класі.
  3. Ви знаєте, що barналежить до Worldкласу, іs є локальною змінною, оголошеною в цьому методі.

Звичайно, щоразу, коли щось розробляєш, ти створюєш правила. Таким чином , при розробці вашого API або проекту, якщо ваші правила включають в себе «якщо хто - то відкриває всі ці вихідні коди з блокнотом, він повинен застрелити його / себе в голові» , то ви абсолютно нормально , щоб не робити цього .


чудова відповідь @Jai
gaurav

Першою причиною зйомки було б заняття з написання кількох рядків кодом 10k, особливо якщо код вже розділений на різні класи, які не потрібно
вкладати

@LuCio Lol true xD
Jai

7

Якщо у вас немає назв змінних, що перекриваються, це справді просто для ясності, коли ви читаєте код.


1
Коли ви постійно бачите thisключове слово, коли це не обов'язково, це лише код коробки, що ускладнює читання коду.
AxeEffect

Щойно я натрапив на проект з відкритим кодом, який вимагає, щоб усі члени мали префікс "це". Крім того, проект дуже добре написаний, але я спокусився вступити з ними в релігійну дискусію.
LegendLength

4
@AxeEffect Я знаю, що це дійсно старе, але ... thisНЕ ускладнює читання коду lmao.
Ксатенев

4

Відповідь @William Brendel приємно подав три різні випадки використання.

Використовуйте випадок 1:

Офіційна сторінка документації Java на цьому веб-сайті містить такі самі випадки використання.

У методі екземпляра або конструкторі це посилання на поточний об'єкт - об'єкт, метод чи конструктор якого викликається. Ви можете звернутися до будь-якого члена поточного об'єкта з методу екземпляра або конструктора, скориставшись цим.

Він охоплює два приклади:

Використання цього поля та використання цього інструменту з конструктором

Скористайтеся випадком 2:

Інший випадок використання, який не цитується в цій публікації: thisможе використовуватися для синхронізації поточного об'єкта у багатопотоковому додатку для захисту критичного розділу даних та методів.

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

Використовуйте випадок 3:

Реалізація шаблону Builder залежить від використанняthis повернення зміненого об'єкта.

Зверніться до цієї публікації

Тримаючи програму в окремому класі


2

Google відкрив сторінку на сайті Sun, де це трохи обговорюється.

Ви маєте рацію щодо змінної; thisдійсно може бути використаний для диференціації змінної методу від класового поля.

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

Однак я дуже ненавиджу цю конвенцію. Дати дві різні змінні буквально однакові назви - це рецепт помилок. Я дуже віддаю перевагу чомусь такому:

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

Ті самі результати, але без шансу на помилку, на яку ви випадково звертаєтесь, xколи ви насправді мали на увазі посиланняx .

Щодо використання цього методу, ви маєте рацію щодо ефектів; ви отримаєте однакові результати з ним або без нього. Чи можете ви ним користуватися? Звичайно. Чи варто використовувати його? До вас, але, враховуючи, що я особисто вважаю, що це безглуздо багатослів'я, яке не додає ясності (якщо код не забитий повною статичною заявою про імпорт), я не схильний сам його використовувати.


4
Це не конвенція, це механізм визначення рівня програмної мови. Що ви перерахували - використання newX (я віддаю перевагу pX для параметра x) є умовою.
Білл К

@Bill K: Я не розумію відмінності, яку ти робиш. Я можу вибрати ім'я змінної входу x, або newX, або pX, або mangroveThroatWarblerX. Як вирішити дати йому ім'я, ідентичне змінній, яку він встановлює НЕ умову, при цьому попередньо встановивши "нові" чи "р" або "Безкоштовні посилання Monty Python" - це умови?
BlairHippo

3
"Посилання на Gratuitoud Monty Python" - це не умова, це ЗАКОН.
Адам Робінсон

+1: Ми використовуємо інший стандарт іменування для аргументів і змінних методів, ніж для класових змінних з цієї причини. Ми скорочуємо аргументи / метод vars і використовуємо повні слова для змінних класу / екземпляра.
Лоуренс Дол

1
Розв’язування його за допомогою конвенції про іменування - це, гм, умовність. Вирішити це за допомогою мовної функції - я думаю, що вибір ніколи не використовувати цю мову чи завжди використовувати це було б умовою ... Використання цього. кожен раз, коли ви отримуєте доступ до члена, це буде конвенцією. Гадаю, це не має великого значення, я ненавиджу це.
Білл К

2

Нижче наведено способи використання ключового слова "це" у Java:

  1. Використання this ключового слова для позначення змінних екземплярів поточного класу
  2. Використання this() для виклику конструктора поточного класу
  3. Використання thisключового слова для повернення поточного екземпляра класу
  4. Використання thisключового слова як параметра методу

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


1

коли є дві змінні одна змінна екземпляра та інша локальна змінна з тим самим іменем, ми використовуємо це. посилатися на поточний об'єкт виконання, щоб уникнути конфлікту між іменами.


1

thisє посиланням на поточний об'єкт. Він використовується в конструкторі для розрізнення локальної та поточної змінної класу, які мають однакову назву. наприклад:

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

thisтакож можна використовувати для виклику одного конструктора від іншого конструктора. наприклад:

public class circle {
    int x;

    circle() { 
        this(1);
    }

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

0

Чи буде якась різниця, якщо я використовую "x" замість "this.x" в деяких методах?

Зазвичай ні. Але це часом має значення:

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

Якщо я просто використовую "method ()", чи не буде він за замовчуванням застосований до поточного об'єкта?

Так. Але при необхідності this.method()уточнює, що дзвінок робиться цим об’єктом.


0

thisне впливає на отриманий код - це оператор часу компіляції і код, згенерований з або без нього, буде однаковим. Коли вам доведеться ним користуватися, залежить від контексту. Наприклад, ви повинні використовувати його, як ви сказали, коли у вас є локальна змінна, яка затінює змінну класу, і ви хочете звернутися до змінної класу, а не до локальної.

edit: під "результуючим кодом буде той самий" я маю на увазі, звичайно, коли якась змінна в локальному масштабі не приховує ту, що належить до класу. Таким чином

class POJO {
   protected int i;

   public void modify() {
      i = 9;
   }

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

отриманий код обох методів буде однаковим. Різниця буде, якщо якийсь метод оголошує локальну змінну з тим самим іменем

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

0

Що стосується Вільяма Brendel повідомлень і «s dbconfessions питання, щодо корпусу 2 . Ось приклад:

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

}

Я бачив, як це застосовувалося, коли будували стосунки батько-дитина з предметами. Однак зауважте, що це спрощено заради стислості.


0

"Це" ключове слово в java використовується для позначення поточних об'єктів класу.

У Java використовується 6 ключових слів "це"

  1. Доступ до змінної рівня класу : в основному використовується, якщо змінна рівня місцевого рівня та класу однакова
  2. Доступ до методів класу : це поведінка за замовчуванням і її можна ігнорувати
  3. Для виклику іншого конструктора того ж класу
  4. Використання ключового слова "це" як повернене значення : для повернення поточного екземпляра з методу
  5. Передача ключового слова "це" як аргумент методу " Передача": для передачі екземпляра поточного класу як аргументу
  6. це ключове слово як аргумент конструктору : для передачі екземпляра поточного класу як аргументу

посилання: https://stacktraceguru.com/java/this-keyword-in-java


-8

Щоб переконатися, що використовуються члени поточного об'єкта. Випадки, коли безпека потоку викликає занепокоєння, деякі програми можуть змінювати неправильні значення елементів об'єкта, тому це має бути застосовано до члена, щоб використовувати правильне значення елемента об'єкта.

Якщо ваш об'єкт не пов'язаний із безпекою потоку, то немає жодної причини вказувати значення того, хто використовується для об'єкта.


Це насправді не так. Я навіть не впевнений, про яку справу ви думаєте, але приклад може бути корисним, щоб зрозуміти, що ви намагаєтесь сказати.
Девід Бергер

1
Так. Я знаю, що ви пояснюєте, що стосується безпеки ниток. Немає правильної відповіді на це питання, що передбачає безпеку нитки. Якщо "це" необхідно для посилання на правильний об'єкт, то, як тільки він це зробить, метод або атрибут будуть безпечними для потоків, якщо і лише якщо вони синхронізовані. Якщо посилання взагалі неоднозначне, буде неоднозначним, чи є багатопотокова проблема.
Девід Бергер
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.