Наследование в Java относится к способности дочерних классов наследовать или приобретать все нечастные свойства и поведения родительского класса. Наследование является одним из четырех столпов объектно-ориентированного программирования и используется для содействия повторному использованию кода среди классов в иерархии.
В этом уроке мы узнаем о типах наследования, поддерживаемых в Java, и о том, как наследование реализуется в приложении.
1. Что такое наследование в Java?
При наследовании класс расширяет другой класс, чтобы наследовать все его не закрытые члены по умолчанию. Этот класс называется дочерним классом или подклассом. Класс, от которого расширяется дочерний класс, называется родительским классом или суперклассом.
В Java ключевое слово extends используется для наследования между классами.
public class Parent {}public class Child extends Parent { //Child class is extending the Parent class}

2. Наследование в действии
Предположим, у нас есть класс Employee. Класс Employee имеет некоторые атрибуты и методы, которые должны иметь все сотрудники в организации.
В том же приложении могут быть и другие специальные сотрудники, например, Менеджер. Менеджеры являются обычными сотрудниками организации, но, кроме того, у них есть несколько дополнительных атрибутов по сравнению с другими сотрудниками, например, подчиненными или подчиненными.
public class Employee {private Long id;private String firstName;private String lastName;//Getters and Setters}
public class Manager extends Employee {private List<Employee> subordinates;public Manager(long id, String firstName, String lastName, List<Employee> subordinates) {super(id, firstName, lastName);this.subordinates = subordinates;}}
В приведенной выше реализации у сотрудников есть общие атрибуты, такие как id, firstName и lastName; в то время как у менеджера есть только специализированный атрибут subdivides. Чтобы унаследовать все не закрытые члены из класса Employee(в данном случае методы getter и setter), Manager расширяет класс Employee.
Давайте проверим, что класс Manager также наследует атрибуты Employee.
Manager manager = new Manager(1l, "Lokesh", "Gupta", List.of(new Employee(2l, "Alex", "Dave")));System.out.println(manager);
Вывод программы.
Manager{id=1, firstName='Lokesh', lastName='Gupta', subordinates=[Employee{id=2, firstName='Alex', lastName='Dave'}]}
Очевидно, что класс Manager может использовать поля и методы класса Employee.
Теперь рассмотрим, если мы не используем наследование. Тогда мы бы сохранили поля id, firstName и lastName в обоих классах. Это привело бы к дублированию кода, что всегда создает проблемы в обслуживании кода.
3. Типы наследования
В Java наследование может быть одного из четырех типов — в зависимости от иерархии классов.
- Единичное наследование
- Многоуровневое наследование
- Иерархическое наследование
- Множественное наследование
3.1 Единичное наследование
В одиночном наследовании один дочерний класс расширяет один родительский класс. Приведенный выше пример кода(Employee и Manager) является примером одиночного наследования.

3.2 Многоуровневое наследование
При многоуровневом наследовании будет наследование между более чем тремя классами таким образом, что дочерний класс будет выступать в качестве родительского класса для другого дочернего класса. Давайте разберемся с помощью диаграммы.

В приведенном выше примере класс B расширяет класс A, поэтому класс B является дочерним классом класса A. Но C расширяет B, поэтому B является родительским классом C. Таким образом, B является как родительским, так и дочерним классом.
3.3 Иерархическое наследование
При иерархическом наследовании существует один суперкласс, и более одного подкласса расширяют суперкласс.

Эти подклассы B, C, D будут иметь общие члены, унаследованные от A, но они не будут знать о членах друг друга.
3.4 Множественное наследование
При множественном наследовании дочерний класс может наследовать поведение более чем от одного родительского класса.

На диаграмме класс D расширяет классы A и B. Таким образом, D может наследовать не закрытые члены обоих классов. Но в Java мы не можем использовать ключевое слово extends с двумя классами. Так как же будет работать множественное наследование?
До JDK 1.7 множественное наследование в Java было невозможно. Но начиная с JDK 1.8 множественное наследование возможно посредством использования интерфейсов с методами по умолчанию.
4. Доступ к членам родительского класса
В дочернем классе мы можем получить доступ к не закрытым членам родительских классов. Давайте посмотрим, как можно получить доступ к отдельным членам.
4.1 Конструкторы
Конструкторы родительского класса могут быть вызваны через ключевое слово super. Есть только два правила:
- Вызов super() должен быть выполнен из конструктора дочернего класса.
- Вызов super() должен быть первым оператором внутри конструктора.
public class Manager extends Employee {public Manager() {super(); //This must be first statement inside constructor//Other statements}}
4.2 Поля
Неприватные поля-члены могут быть унаследованы в дочернем классе. Мы можем получить к ним доступ с помощью оператора точки, например manager.id. Здесь атрибут id унаследован от родительского класса Employee.
Доступ к закрытым полям-членам должен осуществляться через публичные методы получения и установки.
Manager manager = new Manager(...);manager.getId();manager.getFirstName();manager.getLastName();
Мы должны быть осторожны при работе с полями с одинаковыми именами в родительских и дочерних классах. Помните, что поля-члены не могут быть переопределены. Наличие поля с одинаковым именем скроет поле от родительского класса — при доступе через дочерний класс.
В этом случае атрибут, к которому осуществляется доступ, будет определен на основе типа ссылки. Например, предположим, что Employee и Manager имеют общий рейтинг атрибута. Когда мы вызываем manager.rating, то полученное значение будет определено типом ссылки.
class Employee {int rating = 100;}class Manager extends Employee {int rating = 200;}Manager manager = new Manager();System.out.println(manager.rating); //200Employee mgrEmployee = new Manager();System.out.println(mgrEmployee.rating); //100
В приведенном выше примере, несмотря на то, что мы оба раза создаем экземпляр Manager, значение рейтинга отличается, поскольку оно ссылается на тип ссылки.
4.3 Методы
Дочерние классы могут напрямую обращаться к не закрытым методам родительского класса, используя это ключевое слово. Дочерний класс не может обращаться к закрытым методам родительского класса.
В следующем примере класс Manager может получить доступ к открытым методам получения и установки в методе toString().
public class Manager extends Employee {private List<Employee> subordinates;@Overridepublic String toString() {return "Manager{" +"id=" + getId() +", firstName='" + getFirstName() + '\'' +", lastName='" + getLastName() + '\'' +", subordinates=" + subordinates +'}';}}
Обратите внимание, что если родительский и дочерний классы имеют не закрытый метод с одинаковым именем, то доступ к методу будет осуществляться из фактического типа экземпляра.
class Employee {public int getRating() {return 100;}}class Manager extends Employee {public int getRating() {return 200;}}Manager manager = new Manager();System.out.println(manager.getRating()); //200Employee mgrEmployee = new Manager();System.out.println(mgrEmployee.getRating()); //200
5. Заключение
Давайте подведем итог тому, что мы узнали о наследовании в Java:
- Наследование также известно как связь IS-A.
- Это позволяет дочернему классу наследовать не закрытые члены родительского класса.
- В Java наследование осуществляется с помощью ключевого слова extends.
- Начиная с Java 8, вы можете использовать интерфейсы с методами по умолчанию для реализации множественного наследования.
- Доступ к полям-членам осуществляется из класса ссылочного типа.
- Доступ к методам-членам осуществляется из реальных типов экземпляров.
Если у вас возникнут какие-либо вопросы, напишите их в разделе комментариев.