Одиночное и многоуровневое наследование
Часть раздела Объектно-ориентированное программирование путешествия по Java на Coddy — урок 25 из 87.
До сих пор мы видели, как классы расширяют один родительский класс напрямую. Но наследование может формировать различные структуры в зависимости от того, как классы связаны друг с другом. Давайте рассмотрим два основных паттерна: одиночное наследование и многоуровневое наследование.
Одиночное наследование — это то, что мы использовали до сих пор. Класс расширяет ровно один родительский класс напрямую:
public class Animal { }
public class Dog extends Animal { }
public class Cat extends Animal { }Здесь и Dog, и Cat наследуются от Animal, но они не наследуются друг от друга. У каждого потомка есть один прямой родитель.
Многоуровневое наследование создает цепочку, в которой класс расширяет другой класс, который, в свою очередь, расширяет еще один класс:
public class Animal {
public void eat() {
System.out.println("Eating");
}
}
public class Mammal extends Animal {
public void breathe() {
System.out.println("Breathing");
}
}
public class Dog extends Mammal {
public void bark() {
System.out.println("Barking");
}
}В этой цепочке Dog наследуется от Mammal, которое наследуется от Animal. Объект Dog имеет доступ ко всем методам из всей цепочки:
Dog dog = new Dog();
dog.eat(); // От Animal
dog.breathe(); // От Mammal
dog.bark(); // От DogПомните, что Object находится на вершине каждой цепочки. Таким образом, наш Dog на самом деле имеет четыре уровня: Object -> Animal -> Mammal -> Dog. Цепочка конструкторов проходит через все эти уровни при создании нового объекта.
Задание
ЛегкоДавайте построим иерархию транспорта, которая демонстрирует как одиночное, так и многоуровневое наследование. Вы создадите цепочку классов, где каждый уровень добавляет новые возможности, показывая, как методы наследуются через несколько уровней.
Вы организуете свой код в четырех файлах:
Vehicle.java: Создайте базовый класс на вершине вашей иерархии. У каждого транспортного средства должно быть:- Приватное поле для
brand(String) - Конструктор, принимающий бренд
- Метод
getBrand(), который возвращает бренд - Метод
move(), который выводит:[brand] is moving
- Приватное поле для
LandVehicle.java: Создайте класс, который расширяет Vehicle, представляя средний уровень вашей многоуровневой цепочки. Наземные транспортные средства добавляют специфическое для земли поведение:- Приватное поле для
wheels(int) - Конструктор, который принимает brand и wheels, используя
super(brand)для родительской части - Метод
getWheels(), который возвращает количество колес - Метод
honk(), который выводит:[brand] honks!
- Приватное поле для
Car.java: Создайте класс, который расширяет LandVehicle, завершая вашу треххуровневую цепочку наследования. Автомобили добавляют свои собственные специализированные функции:- Приватное поле для
model(String) - Конструктор, который принимает brand, wheels и model, используя
super(brand, wheels) - Метод
getModel(), который возвращает модель - Метод
displayInfo(), который выводит:[brand] [model] with [wheels] wheels
- Приватное поле для
Main.java: Продемонстрируйте, как объект Car имеет доступ к методам со всех трех уровней иерархии. Вы получите три входных значения: brand (String), wheels (int) и model (String). Создайте Car и вызовите эти методы по порядку:move()— унаследован от Vehicle (прародитель)honk()— унаследован от LandVehicle (родитель)displayInfo()— определен в самом Car
Вы получите три входных значения: название бренда, количество колес и название модели.
Ваш вывод должен содержать три строки, демонстрирующие, как объект Car может использовать методы с каждого уровня своей цепочки наследования — от высокоуровневого Vehicle до своего собственного класса!
Шпаргалка
Java поддерживает различные структуры наследования. Двумя основными паттернами являются одиночное наследование и многоуровневое наследование.
Одиночное наследование происходит, когда класс расширяет ровно один родительский класс напрямую:
public class Animal { }
public class Dog extends Animal { }
public class Cat extends Animal { }И Dog, и Cat наследуются от Animal, но не друг от друга.
Многоуровневое наследование создает цепочку, в которой класс расширяет другой класс, который, в свою очередь, расширяет еще один класс:
public class Animal {
public void eat() {
System.out.println("Eating");
}
}
public class Mammal extends Animal {
public void breathe() {
System.out.println("Breathing");
}
}
public class Dog extends Mammal {
public void bark() {
System.out.println("Barking");
}
}При многоуровневом наследовании дочерний класс имеет доступ ко всем методам из всей цепочки наследования:
Dog dog = new Dog();
dog.eat(); // От Animal
dog.breathe(); // От Mammal
dog.bark(); // От DogКаждая иерархия классов имеет Object на вершине. Цепочка вызовов конструкторов проходит через все уровни при создании нового объекта.
Попробуйте сами
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// Считать входные данные
String brand = scanner.nextLine();
int wheels = scanner.nextInt();
scanner.nextLine(); // пропустить символ новой строки
String model = scanner.nextLine();
// TODO: Создать объект Car с введенными значениями
// TODO: Вызвать move() — унаследовано от Vehicle (прародитель)
// TODO: Вызвать honk() — унаследовано от LandVehicle (родитель)
// TODO: Вызвать displayInfo() — определено в самом Car
}
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Внешние файлыВведение в ООПКлассы и объектыКлючевое слово thisМетодыПоля (атрибуты)Метод-конструкторПерегрузка конструкторовИтоги — Простой калькулятор4Наследование
Основы наследования (extends)Ключевое слово superПереопределение методов (@Override)Цепочка конструкторовКласс ObjectОдиночное и многоуровневое наследованиеПочему нет множественного наследования классовИтоги — Иерархия сотрудников7Специальные методы и класс Object
Метод toString()equals() и hashCode()Метод clone()compareTo() и ComparableИнтерфейс ComparatorПовторение — Кастомная сортировка2Модификаторы доступа и инкапсуляция
Обзор уровней доступаМетоды геттеры и сеттерыСокрытие данныхКлючевое слово finalИтоги — Менеджер банковского счета5Полиморфизм
Основы перегрузки методовПереопределение методов (Run-Time)Upcasting и DowncastingОператор instanceofАбстрактные классы и методыИтоги: Калькулятор фигур8Продвинутые концепции ООП
Композиция против наследованияАгрегация против композицииВнутренние, вложенные и анонимные классыEnums и методы перечисленийRecords (Java 16+)Sealed-классы (Java 17+)11Паттерны проектирования. Часть 1
Введение в паттерны проектированияПаттерн SingletonПаттерн FactoryПаттерн BuilderПаттерн ObserverПаттерн Strategy3Свойства класса и статические члены
Переменные экземпляра и статические переменныеСтатические методыСтатические блокиКонстанты (static final)Итоги: Счетчик и утилиты6Интерфейсы и абстрактные классы
Введение в интерфейсыРеализация интерфейсовРеализация нескольких интерфейсовDefault и Static методы в интерфейсахАбстрактные классы vs ИнтерфейсыФункциональные интерфейсыИтоги — Платежная система9Обобщения
Введение в обобщенияОбобщенные классыОбобщенные методыОграниченные параметры типаСимволы подстановки (Wildcards: ?, extends, super)Итоги — Обобщенный контейнер12Паттерны проектирования. Часть 2
Паттерн «Команда»Паттерн «Адаптер»Паттерн «Декоратор»Паттерн «Шаблонный метод»Паттерн «Состояние»Паттерн «Компоновщик»Паттерн «Итератор»