По какой причине конструктор базового класса не может быть переопределён в классе-наследнике?
Конструкторы не являются наследуемыми методами и не участвуют в полиморфном вызове. Конструктор принадлежит конкретному классу, поэтому в классе-наследнике можно только объявить собственный конструктор, который явно или неявно вызывает конструктор базового класса через super.
В объектно-ориентированных языках конструктор отвечает не за обычное поведение объекта, а за создание экземпляра и установку его начального состояния. Разделение конструкторов и методов предотвращает ситуацию, при которой вызов конструктора зависел бы от фактического типа ещё не полностью созданного объекта.
Такой подход позволяет строить объект по цепочке: сначала инициализируется базовая часть, затем добавляется состояние подкласса. При этом обычные экземплярные методы могут быть полиморфными, а конструкторы — нет.
Если ошибочно считать конструктор переопределяемым методом, можно ожидать, что вызов конструктора базового класса автоматически выберет конструктор подкласса. Это невозможно: до завершения конструктора базового класса состояние подкласса ещё не гарантировано.
Кроме того, конструкторы не наследуются по имени и сигнатуре. Если подкласс не объявил ни одного конструктора, компилятор может добавить конструктор без аргументов, но это будет новый конструктор подкласса, а не унаследованный конструктор суперкласса.
При создании объекта Java сначала выбирает конструктор фактического класса. В начале его выполнения должен быть вызван конструктор суперкласса — явно через super(...) или неявно через super().
У Child нет конструктора, переопределяющего Base(int): у них разные классы-владельцы и разные имена. Вызов super(10) — это не полиморфный вызов, а строгое обращение к выбранному конструктору непосредственного суперкласса.
Если в базовом классе нет конструктора без аргументов, подкласс обязан явно вызвать доступный конструктор суперкласса. Конструктор нельзя объявить abstract, static, final или override; эти признаки относятся к механизму методов, а не к созданию объектов.
Базовый класс хранит обязательный идентификатор, а подкласс добавляет сетевые настройки. Разработчик оставляет в подклассе конструктор без явного вызова super и ожидает, что Java сама выберет подходящий конструктор базового класса.
Возможны два решения. Добавление конструктора без аргументов в базовый класс упрощает создание подклассов, но позволяет создавать потенциально невалидные объекты. Явный вызов параметризованного конструктора из подкласса требует больше кода, зато гарантирует передачу обязательных данных.
Обычно выбирают второй вариант: базовый класс не предоставляет фиктивное состояние по умолчанию, а каждый подкласс явно вызывает подходящий конструктор. В результате ошибки инициализации обнаруживаются компилятором, а не во время работы программы.
Нет. Конструктор может напрямую вызвать только конструктор непосредственного суперкласса через super(...). Конструкторы более дальних предков вызываются опосредованно по цепочке конструкторов.
super?Компилятор вставит вызов super() в начало конструктора, если это допустимо. Если у непосредственного суперкласса нет доступного конструктора без аргументов, код не скомпилируется.
Метод может быть переопределён, поэтому вызов из конструктора базового класса способен попасть в реализацию подкласса. Конструктор подкласса при этом ещё не выполнялся, и его поля могут иметь только значения по умолчанию. Сам конструктор подкласса не выбирается полиморфно: он запускается как часть заранее выбранного процесса создания объекта.