Абстрактные классы и методы в Java - Вопросы
Всего: 5 вопросов
1. Что такое абстрактный класс в Java и можно ли создать его объект?
Что такое абстрактный класс в Java и можно ли создать его объект?
Абстрактный класс — это класс, объявленный с модификатором abstract. Он служит общим предком для подклассов и описывает, что они умеют, не говоря как. Создать его объект напрямую нельзя: строка new Figure(10, 10) даёт ошибку компиляции Figure is abstract; cannot be instantiated, даже если у класса есть конструктор.
Зато тип абстрактного класса можно использовать для ссылок на объекты наследников — ради этого абстракция и нужна:
Figure figure = new Rectangle(10, 20); // так можно
System.out.println(figure.calculateArea());
Исключение только на первый взгляд — анонимный подкласс: запись new Figure(10, 10) { public double calculateArea() { return 0; } } компилируется, потому что создаётся объект безымянного наследника, а не самого Figure.
2. Что такое абстрактный метод, как он объявляется и какие модификаторы с ним несовместимы?
Что такое абстрактный метод, как он объявляется и какие модификаторы с ним несовместимы?
Абстрактный метод — это метод без реализации: есть сигнатура, но нет тела. Вместо фигурных скобок сразу ставится точка с запятой:
abstract тип имяМетода(списокПараметров);
public abstract double calculateArea();
Правила: объявить его можно только внутри абстрактного класса или интерфейса; он должен быть реализован в первом неабстрактном наследнике (промежуточный наследник может остаться абстрактным и передать обязанность дальше); он не может быть одновременно static, final или private — статический метод не переопределяется, final запрещает переопределение, а private не виден наследнику. Метод с пустым телом { } — это не абстрактный метод, а обычный: переопределять его никто не обязан.
3. Зачем абстрактному классу конструктор и поля, если объектов у него не бывает?
Зачем абстрактному классу конструктор и поля, если объектов у него не бывает?
Конструктор абстрактного класса инициализирует унаследованную часть состояния и вызывается из конструктора наследника через super(...):
public abstract class Figure {
double dimension1;
double dimension2;
public Figure(double dimension1, double dimension2) {
this.dimension1 = dimension1;
this.dimension2 = dimension2;
}
public abstract double calculateArea();
}
public class Rectangle extends Figure {
public Rectangle(double dimension1, double dimension2) {
super(dimension1, dimension2); // вызов конструктора абстрактного класса
}
@Override
public double calculateArea() {
return dimension1 * dimension2;
}
}
Если явного вызова super(...) нет, компилятор подставит super() сам — и если конструктора без параметров у абстрактного класса не окажется, наследник не скомпилируется. Сам конструктор абстрактным быть не может: конструкторы не наследуются и не переопределяются.
4. Чем абстрактный класс отличается от интерфейса и что выбрать?
Чем абстрактный класс отличается от интерфейса и что выбрать?
Ключевые отличия:
- Количество: унаследовать можно только один класс, а интерфейсов реализовать сколько угодно.
- Состояние: у абстрактного класса любые поля, в интерфейсе только константы
public static final. - Конструктор: у абстрактного класса есть, у интерфейса нет.
- Модификаторы доступа: в абстрактном классе любые, включая
protectedиprivate; в интерфейсе члены по умолчаниюpublic.
После появления default-методов в Java 8 граница стала тоньше, но не исчезла. Абстрактный класс берут, когда наследники — вариации одной сущности с общим состоянием и готовым кодом. Интерфейс берут, когда нужен контракт-роль для не связанных между собой классов или когда одному классу нужно несколько таких ролей.
5. Может ли абстрактный класс не иметь ни одного абстрактного метода?
Может ли абстрактный класс не иметь ни одного абстрактного метода?
Да. Правило работает только в одну сторону: класс с хотя бы одним абстрактным методом обязан быть абстрактным, но обратное неверно — класс может быть абстрактным без единого абстрактного метода:
public abstract class BaseConfig {
public String name() {
return "default";
}
}
// new BaseConfig(); — ошибка компиляции: cannot be instantiated
Такой класс тоже нельзя инстанцировать — это законный способ сказать «пользуйтесь наследниками, а не мной». В JDK так сделаны, например, java.util.AbstractList и java.util.Calendar: они содержат готовый код, а наследнику остаётся дописать лишь то, что действительно уникально.