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