В этой истории мы узнаем о ключевом слове super в Java с помощью примеров. Ключевое слово super в Java используется в подклассах для доступа к членам суперкласса (атрибутам, конструкторам и методам).

Использование ключевого слова super

  1. Для вызова методов суперкласса, которые переопределены в подклассе.
  2. Для доступа к атрибутам (полям) суперкласса, если и суперкласс, и подкласс имеют атрибуты с одинаковыми именами.
  3. Для явного вызова суперкласса без аргументов (по умолчанию) или параметризованного конструктора из конструктора подкласса.

Давайте разберемся с каждым из этих применений.

Доступ к переопределенным методам суперкласса

Если методы с одинаковыми именами определены и в суперклассе, и в подклассе, метод в подклассе переопределяет метод в суперклассе. Это называется переопределением метода.

class Animal {

  // overridden method
  public void display(){
    System.out.println("I am an animal");
  }
}

class Dog extends Animal {

  // overriding method
  @Override
  public void display(){
    System.out.println("I am a dog");
  }

  public void printMessage(){
    display();
  }
}

class Main {
  public static void main(String[] args) {
    Dog dog1 = new Dog();
    dog1.printMessage();
  }
}

Вывод

I am a dog

В этом примере, создав объект dog1 класса Dog, мы можем вызвать его метод printMessage(), который затем выполняет оператор display().

Поскольку display() определен в обоих классах, метод подкласса Dog переопределяет метод надкласса Animal. Следовательно, вызывается display() подкласса.

Что делать, если необходимо вызвать переопределенный метод суперкласса?

Мы используем super.display(), если необходимо вызвать переопределенный метод display() суперкласса Animal.

class Animal {

  // overridden method
  public void display(){
    System.out.println("I am an animal");
  }
}

class Dog extends Animal {

  // overriding method
  @Override
  public void display(){
    System.out.println("I am a dog");
  }

  public void printMessage(){

    // this calls overriding method
    display();

    // this calls overridden method
    super.display();
  }
}

class Main {
  public static void main(String[] args) {
    Dog dog1 = new Dog();
    dog1.printMessage();
  }
}

Вывод

I am a dog
I am an animal

Доступ к атрибутам суперкласса

Суперкласс и подкласс могут иметь атрибуты с одинаковыми именами. Мы используем ключевое слово super для доступа к атрибуту суперкласса.

class Animal {
  protected String type="animal";
}

class Dog extends Animal {
  public String type="mammal";

  public void printType() {
    System.out.println("I am a " + type);
    System.out.println("I am an " + super.type);
  }
}

class Main {
  public static void main(String[] args) {
    Dog dog1 = new Dog();
    dog1.printType();
  }
}

Вывод

I am a mammal
I am an animal

В этом примере мы определили один и тот же тип поля экземпляра как в суперклассе Animal, так и в подклассе Dog.

Затем мы создали объект dog1 класса Dog. Затем с помощью этого объекта вызывается метод printType().

Внутри функции printType()

  • type относится к атрибуту подкласса Dog.
  • super.type относится к атрибуту суперкласса Animal.

Следовательно, System.out.println("I am a " + type); печатает я млекопитающее. И System.out.println("I am an " + super.type); печатает Я животное.

Использование super() для доступа к конструктору суперкласса

Как известно, при создании объекта класса автоматически вызывается его конструктор по умолчанию. Чтобы явно вызвать конструктор суперкласса из конструктора подкласса, мы используем super(). Это особая форма ключевого слова super. super() может использоваться только внутри конструктора подкласса и должен быть первым оператором.

class Animal {

  // default or no-arg constructor of class Animal
  Animal() {
    System.out.println("I am an animal");
  }
}

class Dog extends Animal {

  // default or no-arg constructor of class Dog
  Dog() {

    // calling default constructor of the superclass
    super();

    System.out.println("I am a dog");
  }
}

class Main {
  public static void main(String[] args) {
    Dog dog1 = new Dog();
  }
}

Вывод

I am an animal
I am a dog

Здесь, когда создается объект dog1 класса Dog, он автоматически вызывает конструктор по умолчанию или конструктор без аргументов этого класса. Внутри конструктора подкласса оператор super() вызывает конструктор суперкласса и выполняет операторы внутри него. Следовательно, мы получаем вывод Я животное.

Затем поток программы возвращается к конструктору подкласса и выполняет оставшиеся операторы. Таким образом, я собака будет напечатана. Однако использование super() не является обязательным. Даже если super() не используется в конструкторе подкласса, компилятор неявно вызывает конструктор по умолчанию суперкласса.

Так зачем использовать избыточный код, если компилятор автоматически вызывает super()?

Это требуется, если параметризованный конструктор (конструктор, принимающий аргументы) суперкласса должен вызываться из конструктора подкласса. Параметризованный super() всегда должен быть первым оператором в теле конструктора подкласса, иначе мы получим ошибку компиляции.

class Animal {

  // default or no-arg constructor
  Animal() {
    System.out.println("I am an animal");
  }

  // parameterized constructor
  Animal(String type) {
    System.out.println("Type: "+type);
  }
}

class Dog extends Animal {

  // default constructor
  Dog() {

    // calling parameterized constructor of the superclass
    super("Animal");

    System.out.println("I am a dog");
  }
}

class Main {
  public static void main(String[] args) {
    Dog dog1 = new Dog();
  }
}

Вывод

Type: Animal
I am a dog

Компилятор может автоматически вызвать конструктор без аргументов. Однако он не может вызывать параметризованные конструкторы. Если необходимо вызвать параметризованный конструктор, нам нужно явно определить его в конструкторе подкласса.

Обратите внимание, что в приведенном выше примере мы явно вызвали параметризованный конструктор super("Animal"). В этом случае компилятор не вызывает конструктор суперкласса по умолчанию, поскольку один конструктор может вызывать только один конструктор. Кроме того, super() должен быть в первой строке, если компилятор вызывает конструктор суперкласса по умолчанию, это будет вторая строка, а это противоречит правилам.