Абстрактные классы и методы
Часть раздела Объектно-ориентированное программирование путешествия по Java на Coddy — урок 32 из 87.
Иногда вам нужно определить класс, который служит чертежом, но никогда не должен создаваться напрямую. Например, общий класс Shape имеет смысл в качестве родительского, но как бы выглядела «фигура» без конкретной формы? Именно здесь на помощь приходят абстрактные классы.
Абстрактный класс объявляется с помощью ключевого слова abstract, и его экземпляр не может быть создан. Он может содержать как обычные методы с реализацией, так и абстрактные методы, которые не имеют тела:
public abstract class Shape {
protected String color;
public Shape(String color) {
this.color = color;
}
// Абстрактный метод - без реализации
public abstract double getArea();
// Обычный метод - имеет реализацию
public String getColor() {
return color;
}
}Абстрактные методы объявляют, что должен делать подкласс, но не как. Любой неабстрактный класс, наследующий абстрактный класс, должен предоставить реализации для всех абстрактных методов:
public class Circle extends Shape {
private double radius;
public Circle(String color, double radius) {
super(color);
this.radius = radius;
}
@Override
public double getArea() {
return Math.PI * radius * radius;
}
}Вы по-прежнему можете использовать абстрактные классы в качестве ссылочных типов, обеспечивая полиморфизм:
Shape shape = new Circle("red", 5.0);
System.out.println(shape.getArea()); // Вызывает реализацию CircleАбстрактные классы идеально подходят в тех случаях, когда подклассы имеют общий код, но каждый из них должен реализовывать определенное поведение по-разному. Они навязывают контракт, позволяя при этом повторно использовать код.
Задание
ЛегкоДавайте создадим систему бытовой техники, которая демонстрирует возможности абстрактных классов. Вы создадите базовый класс Appliance, который определяет, что должен делать каждый прибор, позволяя конкретным типам приборов решать, как именно они это делают.
Вы организуете свой код в четырех файлах:
Appliance.java: Создайте абстрактный класс, который служит чертежом для всех приборов. У каждого прибора есть полеbrand(String) и полеwattage(int). Включите конструктор, который инициализирует оба поля, методы-геттеры для каждого из них и обычный методgetInfo(), который возвращает:[brand] - [wattage]W. Определите абстрактный методoperate(), который должны реализовать подклассы — он представляет собой то, как каждый прибор выполняет свою основную функцию.WashingMachine.java: Создайте конкретный класс, расширяющий Appliance. У стиральных машин есть дополнительное полеcapacity(int), представляющее размер загрузки в кг. Используйтеsuperдля обработки инициализации родительского класса. Реализуйте методoperate(), чтобы он выводил:[brand] washing machine is washing [capacity]kg of clothesMicrowave.java: Создайте еще один конкретный класс, расширяющий Appliance. У микроволновых печей есть полеpower(int), представляющее процент уровня мощности. Реализуйтеoperate(), чтобы он выводил:[brand] microwave is heating at [power]% powerMain.java: Соберите все вместе, используя полиморфизм. Вы получите пять входных данных: название бренда, мощность, вместимость стиральной машины, название другого бренда и уровень мощности микроволновой печи. Создайте WashingMachine и Microwave, затем сохраните их в массиве ссылокAppliance. Пройдите циклом по массиву и для каждого прибора выведите информацию о нем с помощьюgetInfo(), а затем вызовитеoperate().
Вы получите пять входных данных в следующем порядке: первый бренд (String), первая мощность (int), вместимость в кг (int), второй бренд (String) и уровень мощности (int).
Ваш вывод должен содержать четыре строки — для каждого прибора вы увидите строку с информацией, за которой следует описание его работы. Обратите внимание, как абстрактный класс позволяет вам единообразно обращаться с различными приборами, в то время как каждый из них работает по-своему уникально!
Шпаргалка
Абстрактный класс объявляется с использованием ключевого слова abstract и не может быть инстанцирован напрямую. Он служит шаблоном для подклассов:
public abstract class Shape {
protected String color;
public Shape(String color) {
this.color = color;
}
// Абстрактный метод — без реализации
public abstract double getArea();
// Обычный метод — имеет реализацию
public String getColor() {
return color;
}
}Абстрактные методы не имеют тела и должны быть реализованы в неабстрактных подклассах:
public class Circle extends Shape {
private double radius;
public Circle(String color, double radius) {
super(color);
this.radius = radius;
}
@Override
public double getArea() {
return Math.PI * radius * radius;
}
}Абстрактные классы могут использоваться в качестве ссылочных типов для полиморфизма:
Shape shape = new Circle("red", 5.0);
System.out.println(shape.getArea()); // Вызывает реализацию класса CircleАбстрактные классы идеально подходят для случаев, когда подклассы имеют общий код, но должны реализовывать определенное поведение по-разному.
Попробуйте сами
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// Считать входные данные
String brand1 = scanner.nextLine();
int wattage1 = scanner.nextInt();
int capacity = scanner.nextInt();
scanner.nextLine(); // поглотить символ новой строки
String brand2 = scanner.nextLine();
int power = scanner.nextInt();
// TODO: Создать объект WashingMachine с brand1, wattage1 и capacity
// TODO: Создать объект Microwave с brand2, wattage1 (или соответствующей мощностью) и power
// TODO: Создать массив ссылок Appliance и сохранить оба объекта
// TODO: Пройти циклом по массиву и для каждого устройства:
// - Вывести информацию о нем, используя getInfo()
// - Вызвать operate()
}
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
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
Паттерн «Команда»Паттерн «Адаптер»Паттерн «Декоратор»Паттерн «Шаблонный метод»Паттерн «Состояние»Паттерн «Компоновщик»Паттерн «Итератор»