Ответ 1
Физически вы создали единый объект, но концептуально создали 2. Это похоже на то, когда, скажем, родилась девочка: физически она только одна, но концептуально родилась новая женщина, а также новый человек родился, появилось новое чувственное существо, родился новый житель планеты Земля и т.д. Да, точно. Здесь тоже есть отношение наследования (subTyping), и я сделал это нарочно. Чтобы избежать путаницы, вероятно, лучше сказать, что существует только один объект с несколькими гранями; один объект, который является членом разных (супер-) классов одновременно.
Теперь, сказав достаточно о логической части, рассмотрим физическую часть. Единый (физический) объект создается со следующей структурой в памяти
+--------------------------+----------------------------+
| B | C' +
+--------------------------+----------------------------+
Первая часть (B) содержит все поля, унаследованные от суперкласса B из C (если таковые имеются). Вторая часть (C ', и я использую '
для "дополнения" ) содержит все поля, которые являются "проприетарными" для C (то есть не наследуются от B, а определяются самим C). Важно отметить, что созданный объект не запускается на C ', а на B. Это комбинация унаследованных полей с новыми полями, составляющими полный объект.
Теперь, если у B был свой собственный суперкласс A, структура была бы такой:
+--------+-----------------+----------------------------+
| A | B' | C' +
+--------+-----------------+----------------------------+
Важно отметить, что B == A + B'
. Другими словами, C не нужно знать о A. Все, что ему нужно, это его непосредственный суперкласс B, который скрывает его внутреннюю структуру.
Чтобы ответить на конкретные вопросы:
Создает ли конструктор в этом случае только инициализацию переменной я и не создает конкретный объект класса?
Таким же образом, что A, B и C выше были структурно скованы, они также связаны при инициализации. Если бы это было не так, похоже, что девушка в моем первоначальном примере родилась без каких-либо других вещей, которые мы знаем, она также по определению. Это невозможно. Полное противоречие. Таким образом, выполняется процесс построения классов, который включает в себя: инициализацию полей в "нулевом" значении (null
для ссылок и false
для boolean
) и выполнение один конструктор (который может вызывать другие конструкторы).
В этом конкретном случае поле i
инициализируется, выполняется конструктор Inheritance
, поля TestInheritance
(если он имел какой-либо) были бы инициализированы, а затем был бы выполнен конструктор TestInheritance
, Как мы можем точно сказать, какие конструкторы каждого класса? Относительно просто. Что инициировало все, это new TestInheritance()
. Это, очевидно, указывает на то, что конструктор TestInheritance
, у которого нет какого-либо параметра (который существует, иначе возникла ошибка компиляции). Однако этот конструктор явно не вызывает какой-либо конструктор суперкласса (через ключевое слово super(...)
). Как мы видели выше, этого не может быть, и компилятор автоматически вставляет эквивалент super()
, то есть вызов конструктора суперкласса без аргументов (Inheritance()
). Опять же, этот конструктор существует, и все хорошо. Выход был бы:
I am in base class 0
I am in derived class
Конструкторы без параметров называются "конструкторами по умолчанию" по трем основным причинам: - Они обычно очень просты, так как у них нет параметров. - Они вызываются автоматически, когда конструктор подкласса явно не вызывает какой-либо конструктор суперкласса. - Они автоматически предоставляются для этих классов без какого-либо конструктора, написанного программистом. В этом случае конструктор ничего не делает и имеет место только инициализация.
Из того, что я прочитал до сих пор, создается только один объект - производного класса, у которого в нем есть переменная.
Это не совсем правильно. Физически это правда, что был создан только один объект, но он соответствует классу, используемому с new
(TestInheritance
), который в этом случае не имеет полей, но это не имеет значения. Фактически, обе выходные линии печатаются. Концептуально... мы уже упоминали об этом.
Но с момента вызова конструктора базового класса и момента времени, когда конструктор производного класса называется тем, как/где я сохранен в памяти?
Когда выполняется new TestInheritance()
, первое, что происходит до вызова конструкторов, даже до инициализации, заключается в том, что память выделяется для всего объекта,
- Обычно эта память "грязная" и поэтому ее нужно инициализировать.
- Есть пространство для полей TestInheritance
, полей суперкласса и т.д. Даже положение каждого поля внутри объекта в памяти известно заранее.
Итак, еще до того, как вызывается конструктор базового класса, уже выделена память для i
и любого другого поля, просто они "грязные" (не инициализированы).
И что будет в случае, если базовый класс является абстрактным.
Нет никакой разницы. Единственное, что вы сами не можете создавать объекты абстрактного класса. Вы создаете их как часть (конкретного) подкласса. Это похоже на то, что новый человек не может быть рожден сам. Это либо девочка, либо ребенок.
Я был бы очень признателен, если бы знал, что происходит в памяти в разные моменты времени.
Надеюсь, я это сделал.
Если я сказал что-то принципиально неправильное, пожалуйста, дайте мне знать. Я действительно хочу знать, как это работает.
Ничего "принципиально неверного".