User grishin
grishin
27 уровень
Харьков

Разница между ключевыми словами this и super в Java

Статья из группы Архив info.javarush.ru
this и super - это два специальных ключевых слова в Java, которые представляют соответственно текущий экземпляр класса и его суперкласса. Java-программисты часто путают эти слова и обнаруживают слабую осведомленность об их специальных свойствах, о которых нередко спрашивают на интервью по Java Сore. Вот, например, пара вопросов, из того, что сразу приходит на ум, о this и super, Можно ли присвоить другое значение ключевому слову this в Java? и какая разница между ключевыми словами this и super в Java. Не знаете? Ну что ж, здесь я ответа не даю — его можно найти в конце статьи. Разница между ключевыми словами this и super в Java - 1Так вот, как я уже сказал в начале, главное отличие между this и super в Java в том, что this представляет текущий экземпляр класса, в то время как super - текущий экземпляр родительского класса. Вот один из примеров использования переменных this и super — вы наверняка уже видели примеры вызовов конструкторов одного из другого, т.н. вызовы конструкторов по цепочке, это возможно благодаря использованию ключевых слов this и super. Внутри класса для вызова своего конструктора без аргументов используется this(), тогда как super()используется для вызова конструктора без аргументов, или как его ещё называют, конструктора по умолчанию родительского класса. Между прочим, таким способом вызывать можно не только конструктор без аргументов, а и вообще любой другой конструктор, передав ему соответствующие параметры. Скоро мы увидим пример такого использования this и super. Ещё this и super в Java используются для обращения к переменным экземпляра класса и его родителя. Вообще-то, к ним можно обращаться и без префиксов super и this, но только если в текущем блоке такие переменные не перекрываются другими переменными, т.е. если в нем нет локальных переменных с такими же именами, в противном же случае использовать имена с префиксами придется обязательно, но это не беда, т.к. в таком виде они даже более читабельны. Классическим примером такого подхода является использование this внутри конструктора, который принимает параметр с таким же именем, как и у переменной экземпляра. Дальше в статье мы узнаем, какие ещё есть отличия между super и this, и рассмотрим некоторые примеры их использования.

Чем this и super похожи

Прежде чем рассматривать отличия ключевых слов this и super, давайте посмотрим на некоторые их сходства:
  1. И this, и super — это нестатические переменные, соответственно их нельзя использовать в статическом контексте, а это означает, что их нельзя использовать в методе main. Это приведет к ошибке во время компиляции "на нестатическую переменную this нельзя ссылаться из статического контекста". То же самое произойдет, если в методе main воспользоваться ключевым словом super.

  2. И this, и super могут использоваться внутри конструкторов для вызова других конструкторов по цепочке, нпр., this() и super() вызывают конструктор без аргументов наследующего и родительского классов соответственно.
В примере ниже мы сначала передаем вызов из конструктора без аргументов класса B в конструктор этого же класса B, принимающий один параметр типа String, из которого, в свою очередь, с помощью super("") вызывается конструктор с одним аргументом из суперкласса.

class A{
   
    A(){
        System.out.println("Конструктор без аргументов класса A");
    }
   
    A(String args){
        System.out.println("Конструктор с одним аргументом класса A");
    }
}
 
class B extends A{
   
   B(){
        this(""); // вызов конструктора с одним аргументом класса B
        System.out.println("Конструктор без аргументов класса B");
    }
  
   B(String args){
        super(""); // вызов конструктора с одним аргументом класса A
        System.out.println("Конструктор с одним аргументом класса B");
    }
}
 
// Тест-класс и вывод 
public class Test {
   
    public static void main(String args[]) {      
       B b = new B();             
    }
 
}
Вывод: Конструктор с одним аргументом класса A Конструктор с одним аргументом класса B Конструктор без аргументов класса B
  1. Внутри конструктора this и super должны стоять выше всех других выражений, в самом начале, иначе компилятор выдаст сообщение об ошибке. Из чего следует, что в одном конструкторе не может быть одновременно и this(), и super().

Различия в super и this

Теперь мы знаем как использовать ключевые слова super и this и понимаем для чего они нужны. Но есть ещё один вариант использования этих ключевых слов, о котором я не сказал - во Внутренних классах, где с их помощью очень удобно ссылаться на внешний класс, используя форму записи Outer.this для его текущего экземпляра и Outer.super — для его родителя. Не забудьте вместо Outer подставить имя внешнего класса. А теперь давайте кратко перечислим главные отличия между ключевыми словами this и super
  1. переменная this ссылается на текущий экземпляр класса, в котором она используется, тогда как super — на текущий экземпляр родительского класса.

  2. Каждый конструктор при отсутствии явных вызовов других конструкторов неявно вызывает с помощью super() конструктор без аргументов родительского класса, при этом у вас всегда остается возможность явно вызвать любой другой конструктор с помощью либо this(), либо super().
Пожалуй, это все, что можно сказать о различиях между ключевыми словами this и super в Java и о том, как они используются в программах. Как мы увидели, основное их назначение - вызывать один конструктор из другого и ссылаться на переменные экземпляра, объявленные в текущем классе и его родительском классе. Не забывайте, что это не совсем обычные переменные, а сейчас - ответ на мой вопрос, который я задавал в первом параграфе. Нет, переменной this нельзя присвоить новое значение, потому что она объявлена как final. Можете попробовать сделать это в IDE - получите ошибку компиляции "нельзя присвоить новое значение переменной this — она объявлена как final". Оригинал статьи здесь.
Комментарии (79)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
John F Уровень 26
15 июля 2022
Прекрасный пример кода в статье. Посмотрел с дебагером - все понял.
Gedonist Уровень 16, Москва, Russian Federation
23 июня 2022
Огромная благодарность автору за статью
Виктор Уровень 31, Гомель, Belarus
29 апреля 2022
Не сразу тоже понял, что к чему. Думаю большую часть людей неосознанно смутила вот эти записи: this("") и super(""). Интуитивно нам кажется (по крайней мере мне так показалось), что это вызов конструкторов без параметров (там же пусто :) ). Ну а раз без параметров, мы и смотрим в соответствующие места. Но на самом деле это всё-таки вызов с параметрами, ведь между кавычками может быть всё что угодно. Перепишете код, вставив между кавычками какие-то параметры и всё сразу станет понятно.

class A{

    A(){
        System.out.println("constructor A-1 without args");
    }

    A(String args){ //Step 5
        //Step 6
        System.out.println("constructor A-2 with args= " + args);
        //Step 7 - > Step 8
    }
}

class B extends A{

   B(){  //Step 1
        // step 2 - > Step 3
        this("parametrs_B-1"); 
        // Step 10
        System.out.println("constructor B-1 without args");
        // Step 11 - > Step 12
    }

   B(String args){ //step 3
        // Step 4 -> Step 5
        super("parameters_B-2");
        // Step 8
        System.out.println("constructor B-2 with args= "+args);
        // Step 9 - > Step 10
    }
}


public class Test {

    public static void main(String args[]) {
       //Step 0 -> Step 1
       B b = new B();
       //Step 12
    }

}
Anonymous #2854449 Уровень 18, Москва, Russian Federation
12 марта 2022
class A{ A(){ System.out.println("Конструктор без аргументов класса A"); } A(String args){ System.out.println("Конструктор с одним аргументом класса A"); } } class B extends A{ B(){ this(""); // вызов конструктора с одним аргументом класса B System.out.println("Конструктор без аргументов класса B"); } B(String args){ super(""); // вызов конструктора с одним аргументом класса A System.out.println("Конструктор с одним аргументом класса B"); } } // Тест-класс и вывод public class Test { public static void main(String args[]) { B b = new B(); } } Объясните пожалуйста, что тут происходит?? Мы попадаем в класс B без аргументов, дальше видим this ( с аргументом типа String), который отправляет нас наверх в класс A(с аргументом типа String). 1.Могли ли мы написать вместо this - super? (так же бы попали в класс А(с аргументом типа String??). 2. Почему потом мы попадаем в класс б с одним агрументом (мы же в мейн вызвали класс B без аргументов?). Зачем нам сюда заходить? 3. А потом опять попадаем в B без аргументов но уже игнорируем this, который уже отработал... Помогите разобраться!!! Многочисленные видео не спасают)))
Anonymous #2854449 Уровень 18, Москва, Russian Federation
12 марта 2022
да уж, пример просто жесть, даже без пояснений. Сам понял называется а объяснить нормально не может
Q1R27 Уровень 17, Ukraine
8 марта 2022
тут есть упоминание super и this,с нормальными примерами) https://javarush.ru/groups/posts/1927-konstruktorih-bazovihkh-klassov--
Георгий Уровень 16, Москва, Россия
5 февраля 2022
Никак не мог понять, почему мы создаем объект, вызывая конструкторы без аргумента, но в консоли записи от объектов с аргументами. Для тех, кто так же мучается: поставьте точку дебага на создании объекта в psvm.
Andrii Уровень 18, Kolín, Czech Republic
5 января 2022
В строке 15 допущена ошибка? Там же идет речь о "вызове конструктора без аргументов класса А", не так ли?
Гвазава Сергей Уровень 28, Москва, Россия
25 мая 2021
Вот как не понимал так и не понимаю, куда что выводится. Есть примеры со стрелочками, кто что вызывает? Есть только понимание this для setter . Всё)))) как догнать? нужна визуализация а не буквенное обьяснение... и почему они вызываются в консоле в обратном порядке?
Oleksii Уровень 36, Харьков
8 мая 2021
Отличный пример! Чуть улучшил:

public class Test1 {

    public static void main(String[] args) {
        B b = new B("");
        System.out.println("!");
        A a = new A("");
    }
    }

      class B extends A {
        B() {
            super();
            System.out.println("ДОЧЕРНИЙ класс без аргументов");
        }

        B(String string2) {
            this();
            System.out.println("ДОЧЕРНИЙ класс с аргументом String2");

        }
    }

     class A {
        A() {
            System.out.println("Родительский класс без аргументов");
        }

        A(String string1) {
            System.out.println("Родительский класс с аргументом String1");
        }
    }
Вывод: Родительский класс без аргументов ДОЧЕРНИЙ класс без аргументов ДОЧЕРНИЙ класс с аргументом String2 ! Родительский класс с аргументом String1