Подтвердить что ты не робот

Наследование и создание объектов

Базовый класс:

public class Inheritance {
    int i;
    Inheritance() {
        System.out.println("I am in base class" + i);
    }
}

Производный класс:

public class TestInheritance extends Inheritance {

    TestInheritance() {
        System.out.println("I am in derived class");
    }

    public static void main(String[] args) {
        TestInheritance obj = new TestInheritance();        
    }
}

Это то, что я имею в виду относительно того, что происходит выше.

Когда я создаю объект производного класса по умолчанию, вызывается super() и вызывается конструктор базового класса и инициализирует переменную i.

Теперь, мой вопрос: имеет ли конструктор в этом случае только инициализацию переменной i и не создает конкретный объект класса?

Из того, что я прочитал до сих пор, создается только один объект - производного класса, в котором есть переменная i.

Но с момента вызова конструктора базового класса и момента времени, когда конструктор производного класса называется тем, как /where i хранится в памяти?

И что будет в случае, если базовый класс является абстрактным.

Я был бы очень признателен, если бы знал, что происходит в памяти в разные моменты времени.

Если я сказал что-то принципиально неправильное, пожалуйста, дайте мне знать. Я действительно хочу знать, как это работает.

4b9b3361

Ответ 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 и любого другого поля, просто они "грязные" (не инициализированы).

И что будет в случае, если базовый класс является абстрактным.

Нет никакой разницы. Единственное, что вы сами не можете создавать объекты абстрактного класса. Вы создаете их как часть (конкретного) подкласса. Это похоже на то, что новый человек не может быть рожден сам. Это либо девочка, либо ребенок.

Я был бы очень признателен, если бы знал, что происходит в памяти в разные моменты времени.

Надеюсь, я это сделал.

Если я сказал что-то принципиально неправильное, пожалуйста, дайте мне знать. Я действительно хочу знать, как это работает.

Ничего "принципиально неверного".

Ответ 2

Я думаю, что это общая область путаницы над наследованием. Вы, кажется, поняли, что создан только один объект, что правильно.

Я рекомендую вам подумать о переменных экземпляра в базовом классе как содержащихся в любом суперклассе, так же, как любой общедоступный или защищенный метод в базовом классе доступен из суперкласса.

Когда экземпляр объекта создается, среда выполнения java делает то, что ему нужно сделать, чтобы выделить хранилище для всех вещей, которые необходимы для хранения - главным образом, переменных экземпляра. Таким образом, переменная экземпляра в базовом классе может считаться частью блока памяти, который содержит все переменные экземпляра для объекта, независимо от того, объявлены они в подклассе или суперклассе.

И одна терминологическая коррекция: в вашем коде переменная явно не "инициализирована" - я думаю, что вы хотите спросить о "распределении", т.е. в какой точке переменная имеет свое пространство в памяти. "Инициализация" подразумевает, что переменной присвоено значение, и хотя Java очень хорош в назначении значений по умолчанию для своих переменных, я думаю, что вы выделяете людей в этом случае.