Super in java tutorial

Java super

The super keyword in Java is used in subclasses to access superclass members (attributes, constructors and methods).

Before we learn about the super keyword, make sure to know about Java inheritance.

Uses of super keyword

  1. To call methods of the superclass that is overridden in the subclass.
  2. To access attributes (fields) of the superclass if both superclass and subclass have attributes with the same name.
  3. To explicitly call superclass no-arg (default) or parameterized constructor from the subclass constructor.

Let’s understand each of these uses.

1. Access Overridden Methods of the superclass

If methods with the same name are defined in both superclass and subclass, the method in the subclass overrides the method in the superclass. This is called method overriding.

Example 1: Method overriding

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(); >> 

In this example, by making an object dog1 of Dog class, we can call its method printMessage() which then executes the display() statement.

Читайте также:  Какие версии php существуют

Since display() is defined in both the classes, the method of subclass Dog overrides the method of superclass Animal . Hence, the display() of the subclass is called.

Java overriding example

What if the overridden method of the superclass has to be called?

We use super.display() if the overridden method display() of superclass Animal needs to be called.

Example 2: super to Call Superclass Method

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 

Here, how the above program works.

Working of super in Java

2. Access Attributes of the Superclass

The superclass and subclass can have attributes with the same name. We use the super keyword to access the attribute of the superclass.

Example 3: Access superclass attribute

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 

In this example, we have defined the same instance field type in both the superclass Animal and the subclass Dog .

We then created an object dog1 of the Dog class. Then, the printType() method is called using this object.

Inside the printType() function,

  • type refers to the attribute of the subclass Dog .
  • super.type refers to the attribute of the superclass Animal.

Hence, System.out.println(«I am a » + type); prints I am a mammal . And, System.out.println(«I am an » + super.type); prints I am an animal .

3. Use of super() to access superclass constructor

As we know, when an object of a class is created, its default constructor is automatically called.

To explicitly call the superclass constructor from the subclass constructor, we use super() . It’s a special form of the super keyword.

super() can be used only inside the subclass constructor and must be the first statement.

Example 4: Use of 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 

Here, when an object dog1 of Dog class is created, it automatically calls the default or no-arg constructor of that class.

Inside the subclass constructor, the super() statement calls the constructor of the superclass and executes the statements inside it. Hence, we get the output I am an animal .

Working of super() in Java

The flow of the program then returns back to the subclass constructor and executes the remaining statements. Thus, I am a dog will be printed.

However, using super() is not compulsory. Even if super() is not used in the subclass constructor, the compiler implicitly calls the default constructor of the superclass.

So, why use redundant code if the compiler automatically invokes super()?

It is required if the parameterized constructor (a constructor that takes arguments) of the superclass has to be called from the subclass constructor.

The parameterized super() must always be the first statement in the body of the constructor of the subclass, otherwise, we get a compilation error.

Example 5: Call Parameterized Constructor Using 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(); >> 

The compiler can automatically call the no-arg constructor. However, it cannot call parameterized constructors.

If a parameterized constructor has to be called, we need to explicitly define it in the subclass constructor.

Working of super in case of parameterized constructor.

Note that in the above example, we explicitly called the parameterized constructor super(«Animal») . The compiler does not call the default constructor of the superclass in this case.

Table of Contents

Источник

Super in java tutorial

Одним из ключевых аспектов объектно-ориентированного программирования является наследование. С помощью наследования можно расширить функционал уже имеющихся классов за счет добавления нового функционала или изменения старого. Например, имеется следующий класс Person, описывающий отдельного человека:

class Person < String name; public String getName()< return name; >public Person(String name) < this.name=name; >public void display() < System.out.println("Name: " + name); >>

И, возможно, впоследствии мы захотим добавить еще один класс, который описывает сотрудника предприятия — класс Employee. Так как этот класс реализует тот же функционал, что и класс Person, поскольку сотрудник — это также и человек, то было бы рационально сделать класс Employee производным (наследником, подклассом) от класса Person, который, в свою очередь, называется базовым классом, родителем или суперклассом:

class Employee extends Person < public Employee(String name)< super(name); // если базовый класс определяет конструктор // то производный класс должен его вызвать >>

Чтобы объявить один класс наследником от другого, надо использовать после имени класса-наследника ключевое слово extends , после которого идет имя базового класса. Для класса Employee базовым является Person, и поэтому класс Employee наследует все те же поля и методы, которые есть в классе Person.

Если в базовом классе определены конструкторы, то в конструкторе производного классы необходимо вызвать один из конструкторов базового класса с помощью ключевого слова super . Например, класс Person имеет конструктор, который принимает один параметр. Поэтому в классе Employee в конструкторе нужно вызвать конструктор класса Person. То есть вызов super(name) будет представлять вызов конструктора класса Person.

При вызове конструктора после слова super в скобках идет перечисление передаваемых аргументов. При этом вызов конструктора базового класса должен идти в самом начале в конструкторе производного класса. Таким образом, установка имени сотрудника делегируется конструктору базового класса.

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

public class Program < public static void main(String[] args) < Person tom = new Person("Tom"); tom.display(); Employee sam = new Employee("Sam"); sam.display(); >> class Person < String name; public String getName()< return name; >public Person(String name) < this.name=name; >public void display() < System.out.println("Name: " + name); >> class Employee extends Person < public Employee(String name)< super(name); // если базовый класс определяет конструктор // то производный класс должен его вызвать >>

Производный класс имеет доступ ко всем методам и полям базового класса (даже если базовый класс находится в другом пакете) кроме тех, которые определены с модификатором private . При этом производный класс также может добавлять свои поля и методы:

public class Program < public static void main(String[] args) < Employee sam = new Employee("Sam", "Microsoft"); sam.display(); // Sam sam.work(); // Sam works in Microsoft >> class Person < String name; public String getName()< return name; >public Person(String name) < this.name=name; >public void display() < System.out.println("Name: " + name); >> class Employee extends Person < String company; public Employee(String name, String company) < super(name); this.company=company; >public void work() < System.out.printf("%s works in %s \n", getName(), company); >>

В данном случае класс Employee добавляет поле company, которое хранит место работы сотрудника, а также метод work.

Переопределение методов

Производный класс может определять свои методы, а может переопределять методы, которые унаследованы от базового класса. Например, переопределим в классе Employee метод display:

public class Program < public static void main(String[] args) < Employee sam = new Employee("Sam", "Microsoft"); sam.display(); // Sam // Works in Microsoft >> class Person < String name; public String getName()< return name; >public Person(String name) < this.name=name; >public void display() < System.out.println("Name: " + name); >> class Employee extends Person < String company; public Employee(String name, String company) < super(name); this.company=company; >@Override public void display() < System.out.printf("Name: %s \n", getName()); System.out.printf("Works in %s \n", company); >>

Перед переопределяемым методом указывается аннотация @Override . Данная аннотация в принципе необязательна.

При переопределении метода он должен иметь уровень доступа не меньше, чем уровень доступа в базовом класса. Например, если в базовом классе метод имеет модификатор public, то и в производном классе метод должен иметь модификатор public.

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

class Employee extends Person < String company; public Employee(String name, String company) < super(name); this.company=company; >@Override public void display() < super.display(); System.out.printf("Works in %s \n", company); >>

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

Запрет наследования

Хотя наследование очень интересный и эффективный механизм, но в некоторых ситуациях его применение может быть нежелательным. И в этом случае можно запретить наследование с помощью ключевого слова final . Например:

public final class Person

Если бы класс Person был бы определен таким образом, то следующий код был бы ошибочным и не сработал, так как мы тем самым запретили наследование:

class Employee extends Person

Кроме запрета наследования можно также запретить переопределение отдельных методов. Например, в примере выше переопределен метод display() , запретим его переопределение:

В этом случае класс Employee не сможет переопределить метод display.

Динамическая диспетчеризация методов

Наследование и возможность переопределения методов открывают нам большие возможности. Прежде всего мы можем передать переменной суперкласса ссылку на объект подкласса:

Person sam = new Employee("Sam", "Oracle");

Так как Employee наследуется от Person, то объект Employee является в то же время и объектом Person. Грубо говоря, любой работник предприятия одновременно является человеком.

Однако несмотря на то, что переменная представляет объект Person, виртуальная машина видит, что в реальности она указывает на объект Employee. Поэтому при вызове методов у этого объекта будет вызываться та версия метода, которая определена в классе Employee, а не в Person. Например:

public class Program < public static void main(String[] args) < Person tom = new Person("Tom"); tom.display(); Person sam = new Employee("Sam", "Oracle"); sam.display(); >> class Person < String name; public String getName() < return name; >public Person(String name) < this.name=name; >public void display() < System.out.printf("Person %s \n", name); >> class Employee extends Person < String company; public Employee(String name, String company) < super(name); this.company = company; >@Override public void display() < System.out.printf("Employee %s works in %s \n", super.getName(), company); >>

Консольный вывод данной программы:

Person Tom Employee Sam works in Oracle

При вызове переопределенного метода виртуальная машина динамически находит и вызывает именно ту версию метода, которая определена в подклассе. Данный процесс еще называется dynamic method lookup или динамический поиск метода или динамическая диспетчеризация методов.

Источник

Оцените статью