Когда я должен использовать «это» в классе?


269

Я знаю, что thisотносится к текущему объекту. Но я не знаю, когда мне действительно нужно это использовать. Например, будет ли разница, если я буду использовать xвместо this.xнекоторых методов? Может быть, xбудет ссылаться на переменную, которая является локальной для рассматриваемого метода? Я имею в виду переменную, которая видна только в этом методе.

Как насчет this.method()? Могу ли я использовать это? Должен ли я использовать это. Если я просто использую method(), не будет ли он по умолчанию применяться к текущему объекту?

Ответы:


349

thisКлючевое слово используется в основном в трех ситуациях. Первый и наиболее распространенный - в методах установки для устранения неоднозначности ссылок на переменные. Второе - это когда необходимо передать текущий экземпляр класса в качестве аргумента методу другого объекта. Третий способ вызова альтернативных конструкторов из конструктора.

Случай 1: использование thisдля устранения неоднозначности ссылок на переменные. В методах установки Java мы обычно передаем аргумент с тем же именем, что и закрытая переменная-член, которую мы пытаемся установить. Затем назначьте аргумент xк this.x. Это дает понять, что вы присваиваете значение параметра «имя» переменной экземпляра «имя».

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которое я забыл, поэтому я добавил его к своему ответу. Я не вижу в этом ничего плохого, потому что конечный результат - лучший ответ в целом, что и является целью SO. Я также стараюсь по возможности отдать должное, как и в случае с тринитисом.
Уильям Брендель

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том, что он вызывает intellisense в IDE :)


1
Но затем вы должны вернуться на задний план после того, как посмотрите. Программирование утомительно!
LegendLength

25

Использовать квалификатор нужно только в том this.случае, если другая переменная в текущей области имеет такое же имя, и вы хотите сослаться на член экземпляра (как описывает Уильям). Кроме того, нет разницы в поведении между xи this.x.


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

3
@Chad: Это обычная практика в методах установки Java. Однако, за пределами методов установки, ваши утверждения обычно выполняются.
Уильям Брендель

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

1
@ Чед: Я не могу согласиться с энтузиазмом. Господи, только потому, что "это". позволяет вам дать двум различным переменным одно и то же имя, почему вы хотите?
BlairHippo

2
@Blair: Читая ваш ответ, вы понимаете, что вы не предпочитаете эту практику в методах сеттера, но многие предпочитают (я бы включил себя в этот список). Если у меня есть метод установки, который принимает значение, очевидно, что передаваемое значение должно быть «новым» значением, поэтому добавление «нового» к имени переменной, кажется, добавляет ненужную избыточность в публичный API.
Адам Робинсон

15

«this» также полезно при вызове одного конструктора из другого:

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
Гаурав

Первой причиной для стрельбы было бы написание классов с несколькими строками кода по 10 тыс., Особенно если код уже разбит на разные классы, которые не нужно вкладывать :)
LuCio

@LuCio Lol true xD
Jai

7

Если у вас нет перекрывающихся имен переменных, это действительно просто для ясности, когда вы читаете код.


1
Когда вы постоянно видите thisключевое слово, когда в нем нет необходимости, это просто стандартный код, затрудняющий чтение кода.
AxeEffect

Я только что натолкнулся на проект с открытым исходным кодом, который требует от всех участников префикса «this». Кроме того, проект очень хорошо написан, но я испытываю желание начать с ними религиозные дебаты.
LegendLength

4
@AxeEffect Я знаю, что это действительно старый, но ... thisне делает код труднее читать lmao.
Xatenev

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) является соглашением.
Билл К

@ Билл К: Я не понимаю различий, которые вы делаете. Я могу выбрать имя входной переменной x, или newX, или pX, или mangroveThroatWarblerX. Как выбрать присвоение ему имени, идентичного переменной, которую он устанавливает, а не соглашение, при этом добавляя «новые» или «p» или «бесплатные ссылки на Python» соглашения ARE?
BlairHippo

3
«Gratuitoud Monty Python References» - это не соглашение, это ЗАКОН.
Адам Робинсон

+1: по этой причине мы используем другой стандарт именования для аргументов и переменных метода, чем для переменных класса. Мы сокращаем аргументы / методы и используем полные слова для переменных класса / экземпляра.
Лоуренс Дол

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

Ключевое слово «this» в java используется для ссылки на объекты текущего класса.

Есть 6 вариантов использования этого слова в Java

  1. Доступ к переменной уровня класса : чаще всего используется, если локальная переменная и переменная уровня класса совпадают
  2. Доступ к методам класса : это поведение по умолчанию и его можно игнорировать
  3. Для вызова другого конструктора того же класса
  4. Использование ключевого слова this в качестве возвращаемого значения : для возврата текущего экземпляра из метода
  5. Передача ключевого слова this в качестве аргумента методу Passing: для передачи текущего экземпляра класса в качестве аргумента
  6. это ключевое слово в качестве аргумента для конструктора : для передачи текущего экземпляра класса в качестве аргумента

ссылка: https://stacktraceguru.com/java/this-keyword-in-java


-8

Чтобы убедиться, что используются члены текущего объекта. В случаях, когда важна безопасность потоков, некоторые приложения могут изменять неправильные значения элементов объекта, по этой причине это следует применять к элементу, чтобы использовать правильное значение элемента объекта.

Если ваш объект не связан с безопасностью потока, то нет причин указывать, какое значение элемента объекта используется.


Это действительно не тот случай. Я даже не уверен, о каком случае вы думаете, но пример может помочь понять, что вы пытаетесь сказать.
Дэвид Бергер

1
Да. Я знаю, что вы объясняете, касается безопасности потоков. Нет правильного ответа на этот вопрос, который касается безопасности потоков. Если «this» необходимо для ссылки на правильный объект, то после этого метод или атрибут будут поточно-ориентированными, если и только если они синхронизированы. Если ссылка вообще неоднозначна, будет неоднозначно, является ли многопоточность проблемой.
Дэвид Бергер
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.