Ключевое слово this в Java
1. Что такое ключевое слово this
Ключевое слово this в Java — это ссылка на текущий объект, то есть на тот экземпляр класса, у которого сейчас выполняется метод или конструктор. Внутри любого нестатического метода this доступно автоматически: компилятор передаёт ссылку на объект неявно.
Фактически обращение к полю width внутри метода — это сокращённая запись this.width. Обе строки ниже делают одно и то же:
public class Box {
double width;
void printWidth() {
System.out.println(width); // неявно: this.width
System.out.println(this.width); // явно
}
} Раз запись эквивалентна, возникает вопрос: зачем тогда this вообще нужен? Есть четыре ситуации, где без него не обойтись:
- параметр метода или конструктора перекрывает поле с тем же именем;
- нужно вызвать другой конструктор этого же класса —
this(...); - нужно передать сам объект в другой метод или сохранить его где-то;
- нужно вернуть текущий объект, чтобы строить цепочки вызовов.
Важно
this существует только у объекта. В static-методе, статическом блоке инициализации и в main ключевого слова this нет: компилятор выдаст ошибку non-static variable this cannot be referenced from a static context.
2. Конфликт имён: поле и параметр называются одинаково
Самый частый случай — конструктор или сеттер, у которого параметры названы так же, как поля класса. Внутри такого метода имя width относится к параметру: локальная переменная перекрывает (затеняет) поле класса. Чтобы добраться до поля, используют this:
public class Box {
double width;
double height;
double depth;
Box(double width, double height, double depth) {
this.width = width; // слева — поле объекта, справа — параметр
this.height = height;
this.depth = depth;
}
double getVolume() {
return width * height * depth;
}
} Если назвать параметры по-другому, затенения не будет и this станет не нужен — компилятор и так понимает, где поле, а где параметр:
Box(double w, double h, double d) {
width = w;
height = h;
depth = d;
} На практике первый вариант предпочтительнее: имена параметров совпадают с именами полей, читать такой конструктор проще, а IDE и генераторы кода (в том числе Alt+Insert в IntelliJ IDEA) создают сеттеры именно в таком стиле.
3. Вызов конструктора через this()
Вторая роль ключевого слова — форма this(...). С её помощью один конструктор вызывает другой конструктор этого же класса. Это приём против дублирования кода: вся логика инициализации живёт в одном «главном» конструкторе, а остальные подставляют значения по умолчанию и делегируют работу ему. Такой приём называют цепочкой конструкторов (constructor chaining), и он тесно связан с перегрузкой.
public class Toy {
String name;
int cost;
String manufacturer;
int age;
public Toy(String name, int cost, String manufacturer, int age) {
this(name, cost, manufacturer);
this.age = age;
System.out.println("В конструкторе с четырьмя параметрами");
}
public Toy(String name, int cost, String manufacturer) {
this();
this.name = name;
this.cost = cost;
this.manufacturer = manufacturer;
System.out.println("В конструкторе с тремя параметрами");
}
public Toy() {
System.out.println("В конструкторе по умолчанию");
}
} public class ToyExample {
public static void main(String[] args) {
Toy toy = new Toy("Кукла", 34, "Disney", 3);
}
} Результат программы:
В конструкторе по умолчанию
В конструкторе с тремя параметрами
В конструкторе с четырьмя параметрами Вывод показывает главное: сначала до конца отрабатывает вызванный конструктор и только потом продолжается тело вызывающего. Цепочка раскручивается «вглубь», а печать идёт в обратном порядке.
Правила, которые нужно помнить:
- вызов
this(...)должен быть первой инструкцией конструктора (об исключении из этого правила — в заметке ниже); - в одном конструкторе нельзя одновременно вызвать
this(...)иsuper(...); - цепочка не может замкнуться: конструктор, который прямо или косвенно вызывает сам себя, не компилируется — recursive constructor invocation;
this(...)можно писать только внутри конструктора; из обычного метода вызвать конструктор нельзя.
Что изменилось в современной Java
Формулировка «this() обязан быть первой строкой» верна для Java 8–21. Начиная с Java 25 действуют гибкие тела конструкторов (JEP 513): перед this(...) или super(...) разрешены инструкции пролога — проверка аргументов, вычисление значений. Ограничение осталось одно: до явного вызова конструктора нельзя обращаться к создаваемому экземпляру, то есть читать и писать поля через this. Для собеседований и учебного кода безопаснее придерживаться классического правила.
4. Другие применения this
Передача текущего объекта
Ссылку this можно передать как обычный аргумент — например, зарегистрировать объект в другом классе:
public class Button {
private final EventBus bus;
public Button(EventBus bus) {
this.bus = bus;
}
public void register() {
bus.subscribe(this); // передаём саму кнопку
}
} Возврат this и цепочки вызовов
Если метод возвращает this, вызовы можно объединять в цепочку. На этом построены билдеры и «текучие» (fluent) API:
public class Pizza {
private String size;
private boolean cheese;
public Pizza size(String size) {
this.size = size;
return this;
}
public Pizza cheese(boolean cheese) {
this.cheese = cheese;
return this;
}
@Override
public String toString() {
return "Pizza{size=" + size + ", cheese=" + cheese + "}";
}
} Pizza pizza = new Pizza()
.size("L")
.cheese(true);
System.out.println(pizza); // Pizza{size=L, cheese=true} 5. this и this(): сравнение
Эти две конструкции легко перепутать на собеседовании. Разница между ними такая:
| Конструкция | Что это | Где можно использовать | Типичное применение |
|---|---|---|---|
this | Ссылка на текущий объект | В любом нестатическом методе и конструкторе | this.width = width, передача и возврат объекта |
this(...) | Вызов другого конструктора этого же класса | Только в конструкторе, первой инструкцией | Цепочка конструкторов, значения по умолчанию |
6. На чём чаще всего ошибаются
- Забытый
thisв сеттере. Строкаwidth = width;компилируется без ошибок, но присваивает параметр самому себе — поле остаётся равным0.0. Ошибка проявится только во время работы программы. IDE подсвечивает такие строки предупреждением, не игнорируйте его. thisв статическом контексте. Вmainи любомstatic-методе объекта нет, поэтому обращение кthis— ошибка компиляции.- Замкнутая цепочка конструкторов. Если
A()вызываетA(int), а тот сноваA(), код не соберётся: компилятор поймает рекурсию сразу, до запуска. - Попытка совместить
this(...)иsuper(...). Разрешён только один явный вызов конструктора. - Публикация
thisиз конструктора (this escape). Если передатьthisнаружу до окончания конструктора (зарегистрировать слушателя, положить в статическую коллекцию, запустить поток), другой код увидит объект с недоинициализированными полями, в том числеfinal. Регистрацию выносят в отдельный метод или фабричный метод.
Формальные правила по this и по вызовам конструкторов описаны в спецификации языка: JLS, раздел 8.8.7 Constructor Body.
Часто задаваемые вопросы
Обязательно ли писать this перед полями класса?
Нет. Если локальная переменная или параметр не перекрывает поле, компилятор сам подставляет this, и запись width эквивалентна this.width. Явный this обязателен только там, где имя затенено — обычно в конструкторах и сеттерах, где параметр назван так же, как поле.
Можно ли поставить this() не первой строкой конструктора?
В Java 8-21 нет: компилятор выдаст ошибку call to this must be first statement in constructor. Начиная с Java 25 гибкие тела конструкторов (JEP 513) разрешают инструкции до this(...) и super(...), например проверку аргументов, но обращаться к полям создаваемого объекта в этом прологе по-прежнему нельзя.
На что указывает this внутри лямбда-выражения?
На объект внешнего класса, в котором лямбда объявлена: у лямбды нет собственного this. У анонимного класса поведение другое — там this ссылается на сам экземпляр анонимного класса, а не на объект, в котором он создан.
Видео объяснение
Предпочитаете видеоформат? Посмотрите этот урок с примерами и объяснениями.
Комментарии