Предсказать вывод: абстрактный класс с конструктором
Условие
Какой результат выведет следующий код?
public abstract class OurAbstractClass {
public OurAbstractClass() {
System.out.println("This is abstract class constructor");
}
}
class OurDemoClass extends OurAbstractClass {
public OurDemoClass() {
System.out.println("This is demo class constructor");
}
public static void main(String[] args) {
OurDemoClass ourDemoClass = new OurDemoClass();
}
}
Вопросы
- Что выведет программа?
- В каком порядке вызываются конструкторы?
- Можно ли создать экземпляр абстрактного класса напрямую?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Предсказание вывода: абстрактный класс с конструктором
Результат выполнения
Программа выведет:
This is abstract class constructor
This is demo class constructor
Почему так?
Это классический пример иерархии конструкторов в наследовании. При создании объекта дочернего класса Java автоматически вызывает конструктор родительского класса.
Порядок вызова конструкторов
- Сначала конструктор родителя (
OurAbstractClass) — выводит "This is abstract class constructor" - Потом конструктор дочернего класса (
OurDemoClass) — выводит "This is demo class constructor"
Это происходит, потому что компилятор Java автоматически добавляет вызов super() в конструктор дочернего класса:
class OurDemoClass extends OurAbstractClass {
public OurDemoClass() {
super(); // ← вызов конструктора родителя (компилятор добавляет автоматически)
System.out.println("This is demo class constructor");
}
}
Механизм наследования конструкторов
Правило: Конструктор дочернего класса ВСЕГДА вызывает конструктор родительского класса в начале своего выполнения (явно или неявно).
// ❌ Неправильно (скрытый вызов super())
public class Child extends Parent {
public Child() {
System.out.println("Child constructor");
}
}
// ✓ Эквивалентно (явный вызов super())
public class Child extends Parent {
public Child() {
super(); // явно
System.out.println("Child constructor");
}
}
Важный факт: абстрактный класс имеет конструктор
Вопрос: Можно ли создать объект абстрактного класса напрямую?
// ❌ ОШИБКА! Нельзя инстанцировать абстрактный класс напрямую
OurAbstractClass obj = new OurAbstractClass(); // Compilation error
// ✓ Можно через дочерний класс
OurDemoClass obj = new OurDemoClass(); // OK!
Но! Конструктор абстрактного класса всё равно существует и выполняется при создании дочерних объектов.
Визуализация процесса
Операция: new OurDemoClass()
├─ Начало инициализации объекта
├─ Вызов super() (явно или неявно)
│ └─ Выполнение OurAbstractClass() → выводит сообщение
├─ Выполнение OurDemoClass() → выводит сообщение
└─ Конец инициализации
Пример с явным вызовом super()
public abstract class OurAbstractClass {
public OurAbstractClass() {
System.out.println("Abstract class constructor");
}
}
class OurDemoClass extends OurAbstractClass {
public OurDemoClass() {
super(); // явный вызов конструктора родителя
System.out.println("Demo class constructor");
}
}
public class Main {
public static void main(String[] args) {
OurDemoClass obj = new OurDemoClass();
}
}
/* Вывод:
Abstract class constructor
Demo class constructor
*/
Цепочка наследования (многоуровневое)
public abstract class GrandParent {
public GrandParent() {
System.out.println("1. GrandParent");
}
}
public abstract class Parent extends GrandParent {
public Parent() {
System.out.println("2. Parent");
}
}
public class Child extends Parent {
public Child() {
System.out.println("3. Child");
}
}
public class Main {
public static void main(String[] args) {
new Child();
}
}
/* Вывод:
1. GrandParent
2. Parent
3. Child
*/
Каждый уровень вызывает super() перед своим конструктором!
С параметрами в конструкторах
public abstract class OurAbstractClass {
public OurAbstractClass(String msg) {
System.out.println("Abstract: " + msg);
}
}
class OurDemoClass extends OurAbstractClass {
public OurDemoClass(String msg) {
super(msg); // передаём параметры родителю
System.out.println("Demo: " + msg);
}
}
public class Main {
public static void main(String[] args) {
new OurDemoClass("Hello");
}
}
/* Вывод:
Abstract: Hello
Demo: Hello
*/
Порядок инициализации объекта в Java
1. Выделение памяти для объекта
2. Инициализация полей класса (значения по умолчанию)
3. Вызов конструктора:
3.1. Неявный вызов super() (если не указан явно)
3.2. Инициализация блоков инициализации
3.3. Выполнение тела конструктора
Инициализационные блоки
public abstract class OurAbstractClass {
{
System.out.println("Abstract init block");
}
public OurAbstractClass() {
System.out.println("Abstract constructor");
}
}
class OurDemoClass extends OurAbstractClass {
{
System.out.println("Demo init block");
}
public OurDemoClass() {
System.out.println("Demo constructor");
}
}
/* Вывод:
Abstract init block // инициализационный блок родителя
Abstract constructor // конструктор родителя
Demo init block // инициализационный блок дочернего класса
Demo constructor // конструктор дочернего класса
*/
Различие между static инициализацией и конструктором
public abstract class OurAbstractClass {
static {
System.out.println("Abstract static block (один раз при загрузке класса)");
}
{
System.out.println("Abstract instance block (каждый раз при создании объекта)");
}
public OurAbstractClass() {
System.out.println("Abstract constructor");
}
}
class OurDemoClass extends OurAbstractClass {
static {
System.out.println("Demo static block (один раз при загрузке класса)");
}
{
System.out.println("Demo instance block");
}
public OurDemoClass() {
System.out.println("Demo constructor");
}
}
/* Вывод при первом new OurDemoClass():
Abstract static block
Demo static block
Abstract instance block
Abstract constructor
Demo instance block
Demo constructor
Вывод при втором new OurDemoClass():
Abstract instance block
Abstract constructor
Demo instance block
Demo constructor
*/
Ключевые выводы
✓ Абстрактный класс может иметь конструктор — он будет вызван при создании дочернего объекта
✓ Нельзя создавать экземпляры абстрактного класса напрямую, но его конструктор выполняется через наследование
✓ Порядок: всегда сначала родитель, потом дочерний класс
✓ Super() добавляется автоматически, если не указан явно
✓ Инициализационные блоки выполняются до конструктора
✓ Static блоки выполняются один раз при загрузке класса, не при каждом создании объекта
Вывод
Этот код демонстрирует фундаментальный механизм Java — цепочку конструкторов в иерархии наследования. При интервью важно уметь объяснить порядок выполнения и понимать разницу между статической инициализацией, инстанс-блоками и конструкторами.