Возник достаточно интересный вопрос, на который я пока не смог найти ответ, но уверен, что здесь мне помогут.
Все мы прекрасно знаем о том, что при создании экземпляра класса в памяти у нас осуществляется вызов конструктора, после чего будет создан сам объект. Выполнение кода внутри конструктора сопряжено с инициализацией полей нашего объекта (не статические поля) и вызовом одного из родительских конструкторов (в том случае, если мы не вызываем другой конструктор из того же класса при помощи ключевого слова this). Вот тут мы и подходим к сути вопроса. Допустим, что у нас имеется какой-нибудь произвольный класс, который не наследуется явным образом от какого бы то ни было существующего класса. Что это для нас означает в плане наследования? Это означает то, что класс будет наследоваться напрямую от корневого класса (пусть даже неявно), которым в языке программирования Java является класс Object. Меня немного смущает тот факт, что в нашем произвольном классе мы можем описать конструктор с любым количеством и типами входных параметров (их порядок в коде также может быть каким угодно), в то время, как в самом классе Object имеется всего лишь один единственный конструктор, который не принимает никаких параметров.
Собственно сам вопрос. Происходит ли вообще обращение к конструктору класса Object? Если да, то значит ли это, что всё время вызывается один и тот же конструктор, который не принимает никаких параметров на вход? Или же на основании конструктора наследника автоматически создаётся аналогичный по набору входных параметров конструктор, только уже для класса Object? Да и вообще, правильно ли я понимаю, что при вызове конструктора у класса Object уже не идёт вызов конструктора суперкласса, как это происходит со всеми другими классами (по той простой причине, что класс Object является корневым классом и является единственным классом в языке программирования Java, который не имеет предков, как прямых, так и косвенных)?
Буду благодарен всем, кто поможет хоть как-то прояснить данную ситуацию! :)
Происходит ли вообще обращение к конструктору класса Object?
Да, это прописано в спецификации Java (§8.8.7. Тело конструктора):
If a constructor body does not begin with an explicit constructor invocation and the constructor being declared is not part of the primordial class Object, then the constructor body implicitly begins with a superclass constructor invocation "super();", an invocation of the constructor of its direct superclass that takes no arguments.
Если тело конструктора не начинается с явного вызова конструктора [this или super] и заданный конструктор не является частью первоначального класса Object, то тело конструктора неявно начинается с вызова конструктора суперкласса super(); — выполнения конструктора без аргументов непосредственного класса-предка
Также в п. §8.8.9 указывается, что у каждого класса есть конструктор по умолчанию, даже если он не указан явно.
Это означает, что такой код:
class Test {
}
эквивалентен такому:
class Test {
Test() {
super(); //вызов конструктора Object
}
}
И конструктор класса, который наследуется от Object будет вызывать конструктор Object.
... правильно ли я понимаю, что при вызове конструктора у класса Object уже не идёт вызов конструктора суперкласса, как это происходит со всеми другими классами (по той простой причине, что класс Object является корневым классом и является единственным классом в языке программирования Java, который не имеет предков, как прямых, так и косвенных)?
Правильно понимаете. Предков у Object нет, и конструкторы вызывать не у кого. Для него явно сделано исключение в спецификации.
Для ясности предлагаю рассмотреть что именно происходит на простом примере.
Возьмем следующий код:
public class Test {
public static void main(String[] args) {
new Test();
new Object();
}
}
Сохраним его в файл (Test.java) и скомпилируем. Затем посмотрим какой байт-код сгенерировал компилятор (декомпилировать класс можно с помощью команды javap -c Test.class):
Compiled from "Test.java"
public class Test {
//У класса появился конструктор
public Test();
Code:
0: aload_0
//Который вызывает Object."<init>" (super())
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: new #2 // class Test
3: dup
//При создании объекта прописывается вызов конструктора (test."<init>")
4: invokespecial #3 // Method "<init>":()V
7: pop
8: new #4 // class java/lang/Object
11: dup
12: invokespecial #1 // Method java/lang/Object."<init>":()V
15: pop
16: return
}
По инструкциям видно, что:
Компилятор явно определяет для класса: (1) конструктор по-умолчанию (2) вызов конструктора родителя.
Конструкторы на данном этапе не что иное как обычные методы, которые вызываются через invokespecial и которым даны названия недопустимые в Java ("<init>"), чтобы они не пересекались с другими методами.
Конструкторы (в том числе и Object) и специальные правила, относящиеся к ним, в основном существуют только на этапе компиляции. Компилятор их проверяет, обрабатывает и преобразовывает в явные инструкции вызова методов.
Выполняет инструкции в байт-коде виртуальная машина Java. Именно она определяет что произойдет при вызове invokespecial Test."<init>" и invokespecial Object."<init>". Разработчики виртуальных машин имеют большую свободу интерпретации этих инструкций и применяют сложные алгоритмы оптимизации выполнения кода и выделения памяти.
При создании объекта всегда вызывается конструктор суперкласса. Если в конструкторе вы явно не указываете какой конструктор супер класса будет вызван, то вызовется конструктор по умолчанию (без параметров), но имей те в виду если вы создали в суперклассе конструктор с параметрами, то вам придётся определить и конструктор без параметров явно т.к. он уже будет не виден. Т.е. определив конструктор с параметрами в суперклассе и не определив в нем конструктор без параметров вы не сможете в наследнике создать объект и не указать в его конструкторе super(params) т.к. получите ошибку: в суперклассе отсутствует конструктор по умолчанию.
На счёт класса Object вы правильно понимаете конструирование любого класса заканчивается на конструкторе класса Object. Конструктор вызывается один и тот же. Параметры в вашем конструкторе нужны только вашему классу т.к. он (конструктор) инициализирует ваши переменные о которых суперкласс ничего не знает, соответственно и передавать ему их не надо. А вот если в суперклассе есть инициализируемые поля, то необходимо явно вызывать его конструктор с параметрами. Конструктора создаются один раз.
Происходит ли вообще обращение к конструктору класса Object?
Конечно происходит, поскольку в каждом классе есть конструктор, заданный явно или не явно.
значит ли это, что всё время вызывается один и тот же конструктор, который не принимает никаких параметров на вход?
Конструктор родительского класса вызывается независимо от того используете вы конструктор с параметрами или без.
правильно ли я понимаю, что при вызове конструктора у класса Object уже не идёт вызов конструктора суперкласса
Нет, неправильно. Сначала вызывается конструктор суперкласса, а потом конструктор подкласса. Если в классе есть конструктор, то он вызывается - если нет, то создаётся конструктор по умолчанию, который тоже вызывается, но вы этого не видите.
Апостиль в Лос-Анджелесе без лишних нервов и бумажной волокиты
Основные этапы разработки сайта для стоматологической клиники
Продвижение своими сайтами как стратегия роста и независимости