На JavaRush студентов буквально с первых лекций знакомят с ключевым словом this . И со временем становится понятно, что все же оно означает. Но многие, обернувшись назад, наверное, честно себе скажут, что долго не могли осознать дзен этого ключевого слова. В статье приоткрываем завесу тайн применения ключевика this для тех, кто до сих пор в него не может… Welcome! Если вы возьмете справочник Шилдта по Java, то на 171 странице вы прочитаете о том, что ключевое слово this требуется для того, чтобы метод мог сослаться на вызвавший его объект. На этом, собственно можно было бы и закончить. Но нам нужна конкретика. — 1″ width=»850″/>Как правило, применять this нужно в двух случаях:
Когда у переменной экземпляра класса и переменной метода/конструктора одинаковые имена;
Когда нужно вызвать конструктор одного типа (например, конструктор по умолчанию или параметризированный) из другого. Это еще называется явным вызовом конструктора.
Вот и все, на самом деле не так много, — всего два случая, когда применяется это страшное ключевое слово. Теперь давайте рассмотрим эти две ситуации на примерах.
Пример первый — у переменной экземпляра и метода одинаковые имена
В приведенном выше примере мы создали объект с именем obj класса Main. Затем мы печатаем ссылку на объект obj и ключевое слово this класса. Как мы видим, ссылка на obj и на this одинаковая. Это означает, что this является ссылкой на текущий объект.
Использование ключевого слова this
Существуют несколько ситуаций, в которых используется ключевое слово this.
1. Использование this для различия наименований переменных
В Java не разрешается объявлять две или более переменных с одинаковым именем внутри области видимости (области действия класса или области действия метода). Однако переменные и параметры экземпляра могут иметь одно и то же имя. Вот пример:
class MyClass < // переменная экземпляра int age; // параметр MyClass(int age)< age = age; >>
В этой программе переменная экземпляра и параметр имеют одно и то же имя: age . Поэтому компилятор Java сбит с толку. Чтобы решить проблему мы используем ключевое слово this . Но сначала давайте взглянем на пример, где this не используется:
class Main < int age; Main(int age)< age = age; >public static void main(String[] args) < Main obj = new Main(8); System.out.println("obj.age terminal">obj.age = 0
В приведенном выше примере мы передали конструктору значение 8. Тем не менее, на выходе мы получаем 0. Это связано с тем, что компилятор Java запутался из-за неоднозначности имен между экземпляром переменной и параметром. Теперь давайте перепишем этот код, используя ключевое слово this.
class Main < int age; Main(int age)< this.age = age; >public static void main(String[] args) < Main obj = new Main(8); System.out.println("obj.age terminal">obj.age = 8
Теперь мы получили вполне ожидаемый результат. Это связано с тем, что при вызове конструктора this внутри него заменяется объектом obj, который вызывает конструктор. Следовательно, переменной age присваивается значение 8. Кроме того, если имя параметра и переменной экземпляра различаются, компилятор автоматически добавляет ключевое слово this. Перед вами пример кода:
class Main < int age; Main(int i) < age = i; >>
2. Ключевое слово this с геттерами и сеттерами
Еще одно распространенное использование ключевого слова this — в методах классов setter и getter . Например:
class Main < String name; // метод setter void setName( String name ) < this.name = name; >// метод getter String getName() < return this.name; >public static void main( String[] args ) < Main obj = new Main(); // вызов метода setter и getter obj.setName("Toshiba"); System.out.println("obj.name: "+obj.getName()); >>
чтобы присвоить значение внутри метода setter
для доступа к значению внутри метода getter
3. Использование this в перегрузке конструктора
При работе с перегрузкой конструктора нам может потребоваться вызвать один конструктор из другого конструктора. В данном случае мы не можем вызвать конструктор явно. Вместо этого мы должны использовать this в виде другой формы ключевого слова, то есть this() . Рассмотрим пример кода:
class Complex < private int a, b; // конструктор с двумя параметрами private Complex( int i, int j )< this.a = i; this.b = j; >// конструктор с одним параметром private Complex(int i) < // вызывает конструктор с двумя параметрами this(i, i); >// конструктор без параметров private Complex() < // вызывает конструктор с одним параметром this(0); >@Override public String toString() < return this.a + " + " + this.b + "i"; >public static void main( String[] args ) < // создание объекта класса Complex // вызов конструктора с двумя параметрами Complex c1 = new Complex(2, 3); // вызывает конструктор с одним параметром Complex c2 = new Complex(3); // вызывает конструктор без параметров Complex c3 = new Complex(); // выводим объекты System.out.println(c1); System.out.println(c2); System.out.println(c3); >>
вызова конструктора Complex(int i, int j) из конструктора Complex(int i)
вызова конструктора Complex(int i) из конструктора Complex()
Здесь, когда мы печатаем объект c1 , то объект преобразуется в строку. В этом процессе вызывается toString() . Поскольку мы переопределяем метод toString() внутри нашего класса, то мы получаем вывод в соответствии с этим методом. Одним из огромных преимуществ this() является уменьшение количества дублирующегося кода. Тем не менее, мы всегда должны быть осторожны, если решаем использовать this() . Это связано с тем, что вызов конструктора из другого конструктора добавляет сложность и сам по себе является довольно медленным процессом. Примечание. Вызов одного конструктора из другого конструктора называется явным вызовом конструктора.
4. Передача this в качестве аргумента
Мы также можем использовать ключевое слово this для передачи текущего объекта в качестве аргумента метода. Перед вами пример кода:
class ThisExample < // объявление переменных int x; int y; ThisExample(int x, int y) < // присваиваем значения переменных внутри конструктора this.x = x; this.y = y; // значение x и y перед вызовом add() System.out.println("Before passing this to addTwo() method:"); System.out.println("x = " + this.x + ", y = " + this.y); // вызываем метод add(), передав this в качестве аргумента add(this); // значение x и y после вызова add() System.out.println("After passing this to addTwo() method:"); System.out.println("x = " + this.x + ", y terminal">Перед передачей this методу addTwo(): x = 1, y = -2 После передачи this методу addTwo(): x = 3, y = 0 В этом примере обратите внимание на строку внутри конструктора ThisExample():
add(this);
В ней мы вызываем метод add() , передавая this в качестве аргумента. Поскольку это ключевое слово содержит ссылку на объект класса obj , мы можем изменить значение x и y внутри метода add() .
Если вам понадобится получить ссылку на объект внешнего класса, запишите имя внешнего класса, за которым следует точка, а затем ключевое слово this. Полученная ссылка автоматически относится к правильному типу, известному и проверяемому на стадии компиляции, поэтому дополнительные издержки на стадии выполнения не требуются. Следующий пример показывает, как использовать конструкцию .this:
public class Outer < void f()< System.out.println("Outer.f()"); >public class Inner < public Outer outer()< return Outer.this; >> public Inner inner() < return new Inner(); >public static void main(String[] args) < Outer o = new Outer(); Outer.Inner oi = o.inner(); oi.outer().f(); >>
Иногда бывает нужно приказать другому объекту создать объект одного из его внутренних классов. Для этого перед .new указывается ссылка на другой объект внешнего класса:
public class Outer < public class Inner<>public static void main(String[] args) < Outer o = new Outer(); Outer.Inner oi = o.new Inner(); >>
При создании объекта внутреннего класса указывается не имя внешнего класса Outer, а имя объекта внешнего класса. Это также решает проблему видимости имен для внутреннего класса, поэтому мы не можем использовать запись вида o.new Outer.Inner(). Невозможно создать объект внутреннего класса, не имея ссылки на внешний класс. Но если создать вложенный класс(статический внутренний класс), то ссылка на объект внешнего класса не нужна.