К вопросу о конструкторах в языке программирования Java [закрыт]

206
11 мая 2019, 12:50

Возник достаточно интересный вопрос, на который я пока не смог найти ответ, но уверен, что здесь мне помогут.

Все мы прекрасно знаем о том, что при создании экземпляра класса в памяти у нас осуществляется вызов конструктора, после чего будет создан сам объект. Выполнение кода внутри конструктора сопряжено с инициализацией полей нашего объекта (не статические поля) и вызовом одного из родительских конструкторов (в том случае, если мы не вызываем другой конструктор из того же класса при помощи ключевого слова this). Вот тут мы и подходим к сути вопроса. Допустим, что у нас имеется какой-нибудь произвольный класс, который не наследуется явным образом от какого бы то ни было существующего класса. Что это для нас означает в плане наследования? Это означает то, что класс будет наследоваться напрямую от корневого класса (пусть даже неявно), которым в языке программирования Java является класс Object. Меня немного смущает тот факт, что в нашем произвольном классе мы можем описать конструктор с любым количеством и типами входных параметров (их порядок в коде также может быть каким угодно), в то время, как в самом классе Object имеется всего лишь один единственный конструктор, который не принимает никаких параметров.

Собственно сам вопрос. Происходит ли вообще обращение к конструктору класса Object? Если да, то значит ли это, что всё время вызывается один и тот же конструктор, который не принимает никаких параметров на вход? Или же на основании конструктора наследника автоматически создаётся аналогичный по набору входных параметров конструктор, только уже для класса Object? Да и вообще, правильно ли я понимаю, что при вызове конструктора у класса Object уже не идёт вызов конструктора суперкласса, как это происходит со всеми другими классами (по той простой причине, что класс Object является корневым классом и является единственным классом в языке программирования Java, который не имеет предков, как прямых, так и косвенных)?

Буду благодарен всем, кто поможет хоть как-то прояснить данную ситуацию! :)

Answer 1

Происходит ли вообще обращение к конструктору класса 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>". Разработчики виртуальных машин имеют большую свободу интерпретации этих инструкций и применяют сложные алгоритмы оптимизации выполнения кода и выделения памяти.

Answer 2

При создании объекта всегда вызывается конструктор суперкласса. Если в конструкторе вы явно не указываете какой конструктор супер класса будет вызван, то вызовется конструктор по умолчанию (без параметров), но имей те в виду если вы создали в суперклассе конструктор с параметрами, то вам придётся определить и конструктор без параметров явно т.к. он уже будет не виден. Т.е. определив конструктор с параметрами в суперклассе и не определив в нем конструктор без параметров вы не сможете в наследнике создать объект и не указать в его конструкторе super(params) т.к. получите ошибку: в суперклассе отсутствует конструктор по умолчанию.

На счёт класса Object вы правильно понимаете конструирование любого класса заканчивается на конструкторе класса Object. Конструктор вызывается один и тот же. Параметры в вашем конструкторе нужны только вашему классу т.к. он (конструктор) инициализирует ваши переменные о которых суперкласс ничего не знает, соответственно и передавать ему их не надо. А вот если в суперклассе есть инициализируемые поля, то необходимо явно вызывать его конструктор с параметрами. Конструктора создаются один раз.

Answer 3

Происходит ли вообще обращение к конструктору класса Object?

Конечно происходит, поскольку в каждом классе есть конструктор, заданный явно или не явно.

значит ли это, что всё время вызывается один и тот же конструктор, который не принимает никаких параметров на вход?

Конструктор родительского класса вызывается независимо от того используете вы конструктор с параметрами или без.

правильно ли я понимаю, что при вызове конструктора у класса Object уже не идёт вызов конструктора суперкласса

Нет, неправильно. Сначала вызывается конструктор суперкласса, а потом конструктор подкласса. Если в классе есть конструктор, то он вызывается - если нет, то создаётся конструктор по умолчанию, который тоже вызывается, но вы этого не видите.

READ ALSO
WebDriver не находит нужный элемент

WebDriver не находит нужный элемент

Получаю http://seleniumhqorg/exceptions/no_such_element

185
Положить конкретную переменную в generic тип

Положить конкретную переменную в generic тип

Происходит считывание с текстовика классов Node1(2/3), наследников абстрактного Node с полем T object представляющих Root/Parent/Child дереваПо условию задачи...

199
Failed to load resource: the server responded with a status of 400 () Ошибка при возврате json объекта со scope session

Failed to load resource: the server responded with a status of 400 () Ошибка при возврате json объекта со scope session

Это делаю в первый раз, так что скорее всего явно где-то ошибсяПомогите пожалуйста

187
java.lang.LinkageError

java.lang.LinkageError

Подскажите пожалуйста кто сталкивался такой ошибкой в чем может быть проблема?

226