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

Сколько объектов создано из-за наследования в java?

Скажем, у меня есть три класса:

class A {
    A() {
        // super(); 
        System.out.println("class A");
    }
}
class B extends A {
    B() {
        // super(); 
        System.out.println("class B");
    }
}
class C extends B {
    public static void main(String args[]) {
        C c = new C(); //Parent constructor will get called
    }
}

Когда я создаю экземпляр класса C, он вызывает конструктор суперкласса. Итак, создается ли более одного объекта, который создается? Если создается только один объект, то как супер(), как конструктор другого класса? Метод super() внутренне создает объект? Я знаю, что конструктор также является методом (я могу ошибаться).

Мои вопросы:

  • Сколько всего объекта создается в этом случае?
  • Если создается один объект, то как Super() внутренне вызывает конструктор родительского класса?
4b9b3361

Ответ 1

Отличный вопрос. То, что вы исследуете, - это то, как Java инициализирует объекты - и есть ряд шагов.

Я знаю, что конструктор также является методом (возможно, я ошибаюсь).

Почти правильно. Конструктор - это особый метод. Если вы декомпилируете файл класса, вы увидите, что конструкторы переименовываются в <init>. <init> обрабатывается по-разному от других методов и, например, не может быть вызван явно, за исключением использования ключевого слова new или super. Это настолько фундаментально, что оно реализовано в самой JVM, а не как нечто определенное на языке Java.

Сколько будет создано количество объектов в этом случае.

Создается один объект - экземпляр C.

C дополнительно и одновременно является экземпляром B и экземпляром A, а также Object.

Если создается один объект, то как внутренне super() вызывает родительский класс Constructor. Как Super может вызвать конструктор родительского класса.

Здесь мы входим в инициализацию. Инициализация - это то, как JVM создает новый экземпляр объекта и устанавливает все значения элементов - те, что относятся к определенному классу и классам суперклассов. Существует несколько этапов:

  • Загрузите все ссылочные классы и инициализируйте эти классы. Инициализация класса сама по себе является нетривиальной, поэтому я не буду ее рассматривать. Это стоит прочитать.
  • Выделите кусок памяти для хранения элементов экземпляра, который будет содержать все элементы A, B и C. ПРИМЕЧАНИЕ объясняет один аспект вашего вопроса: как конструкторы базового класса и его подклассов обновляются или ссылаются на один и тот же объект - все члены экземпляра из всех классов хранятся один за другим в той же части памяти.
  • Инициализировать все члены до значения по умолчанию. Например, члены int и float будут установлены в 0 и 0.0f.
  • Выполнить или рассчитать инициализаторы элементов, например:

    private int a = 10;
    private int b = a * 5;
    private String c = Singleton.getInstance().getValue();
    
  • Примечание (1), что инициализация элемента происходит строго в том порядке, в котором члены объявлены в классе. Это означает, что ссылки на членов позже в декларации нарушены:

    private int a = b * 5; // Forward reference; won't compile
    private int b = 10;
    
  • Примечание (2), что в Java используется недоиспользуемое средство для запуска произвольного кода для инициализации значений до выполнения конструктора. Эти кодовые блоки выполняются в это время снова строго в порядке объявления:

    private int a;
    private int b = 1;
    {
        // Initization occurs after b but before c.
        // c cannot be referenced here at all
        int i = SomeClass.getSomeStatic();
        a = i * 2;
    }
    private int c = 99;
    
  • Выполните конструктор C. Конструкторы должны либо напрямую вызывать конструктор из суперкласса, либо компилятор автоматически добавит super() в качестве первой строки конструктора. Это означает, что конструкторы строго выполняются в следующем порядке:

    • Object
    • A
    • B
    • C

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

public class Wrong {
    int a = getB(); // Don't do this!
    int b = 10;
    public int getB() {
         return b;
    }
}

Здесь A инициализируется 0. Это происходит из-за того, что в точке getB(), Java очистило значение B до значения по умолчанию (0), но еще не установило его на 10 во второй фазе инициализации.

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

Ответ 2

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

Докажите создание объекта:

package one;

public class A {
    public static A super_var;

    public A() {
        super_var = this;
        System.out.println("Constrcutor of A invoked");
    }
}

package two;

public class B extends A {
    public static A sub_var;

    public B() {
        sub_var = this;
        System.out.println("Constructor of B invoked");
    }

    public void confirm() {
        if (sub_var == A.super_var)
            System.out.println("There is only one object is created");
        else
            System.out.println("There are more than one object created");
    }

    public static void main(String Args[]) {
        B x = new B();
        x.confirm();
    }
}

Это докажет, что будет создан только один объект.

И около Super(). Я знаю, что он вызывает конструктор класса родителя. и каждый конструктор ahve Super() как первый оператор, как вы упомянули в своем коде. так что вы знаете

Я не знаю, как он внутренне вызывает суперкласс класса.

Надеюсь, это поможет вам понять, что в программе есть только созданный вами способ

Ответ 3

  • Будет создан один и только один объект и т.д. Объект.

  • Вы можете себе представить, что, когда класс A расширяет B, тогда все методы и переменные копируются в класс A.

Ответ 4

  • В вашем случае создается только 1 объект.
  • Когда вызывается конструктор подкласса, он вызывает конструктор супер класса внутри, чтобы инициализировать члены суперкласса.

Вызывающий конструктор не означает, что вы создаете объекты. Объект уже создан при вызове конструктора. Сначала объекты создаются с помощью JVM (i.e память выделяется в куче, а затем вызывается конструктор).

Конструктор предназначен для инициализации элементов объектов.

Ответ 5

Ваши классы будут внутренне преобразованы в нечто подобное

class A
{
    A(){
        super(); 
        System.out.println("class A");
    }
}

class B extends A{
    B(){
        super(); 
        System.out.println("class B");
    }
}

public class C extends B
{
    public static void main(String args[])
    {
        C c  = new C(); //Parent constructor will get call 
    }
}

Сколько будет создано количество объектов в этом случае.

Только один экземпляр C, вызывающий super() только вызывает конструктор родительского класса и не выполняет создать объект

Если создается один объект, то как внутри Super() вызывает родительский class Constructor. Как Super может вызвать родительский класс конструктор.

При создании экземпляра C. C вызывается конструктор, который сначала вызывает конструктор B, который в свою очередь вызывает конструктор A

Ответ 6

Если вы посмотрите на динамику распределения объектов по этому, то должно быть ясно, что с помощью оператора new вы создаете только один объект для каждого оператора. Чтобы прояснить сомнение в том, что существует только один объект, который создается, пройдите через эту программу:

public class A {
    public static int aInstanceCount=0;
    public static A aInstance;
    public String aInstanceVariable;
    A() {
//Super();
        aInstanceCount++;
        aInstanceVariable="aInstanceVar";
        System.out.println("class A");
        aInstance=this;
    }
}

class B extends A {
    public static int bInstanceCount=0;
    public static B bInstance;
    public String bInstanceVariable;
    B() {
//Super();
        bInstanceCount++;
        bInstanceVariable="bInstanceVar";
        System.out.println("class B");
        bInstance=this;
    }
}

class C extends B {
    public static void main(String args[]) {
        int instanceCount=0;
        C c = new C(); //Parent constructor will get call
        if(A.aInstance!=null){
            instanceCount++;
            System.out.println("Value of aInstanceVariable: "+A.aInstance.aInstanceVariable);

        }
        if(B.bInstance!=null){
            instanceCount++;
            System.out.println("Value of bInstanceVariable: "+B.bInstance.bInstanceVariable);
        }
        A a=A.aInstance;
        B b=B.bInstance;
        System.out.println("bInstanceVariable of B earlier: " + B.bInstance.bInstanceVariable);
        //Now we are changing the bInstanceVariable of c which is inherited from B
        c.bInstanceVariable="bInstance After modified by C";
        System.out.println("bInstanceVariable of B after: " + B.bInstance.bInstanceVariable);
        System.out.println("aInstanceVariable of A earlier: " + A.aInstance.aInstanceVariable);
        //Now we are changing the aInstanceVariable of c which is inherited from A
        c.aInstanceVariable="aInstance After modified by C";
        System.out.println("bInstanceVariable of A after: " + A.aInstance.aInstanceVariable);
    }
}

Выход:

class A
class B
Value of aInstanceVariable: aInstanceVar
Value of bInstanceVariable: bInstanceVar
bInstanceVariable of B earlier: bInstanceVar
bInstanceVariable of B after: bInstance After modified by C
aInstanceVariable of A earlier: aInstanceVar
bInstanceVariable of A after: aInstance After modified by C

Если вы заметите, суперконструктор неявно получает вызов каждый раз, если создается объект подкласса, но поскольку оператор new используется только один раз, есть только один объект, который фактически выделяет пространство. И изменяя aInstanceVariable через C объект C, мы фактически меняем aInstanceVariable of aInstance. Таким образом, это ясно доказывает, что на самом деле есть один объект.

Ответ 7

Шаги создания объекта при вызове конструктора для создания объекта:

  • Выполняется выделение памяти с помощью init. Этот init делает системный вызов для выделения памяти для создания объекта.

  • Затем ваш конструктор вызывается для инициализации полей объекта.

  • Затем он вызывает суперкласс класса (если есть суперкласс) и повторения шагов с 1 по 3.

Что вы видите, когда декомпилируете файл класса с помощью javap, отображаются разные вызовы. init делает системный вызов для инициализации выделения памяти, но поле объекта инициализируется при запуске кода конструктора.

Ответ 8

Я не уверен, как полиморфизм/переопределение работает во время GC.

Но стоит попробовать переопределить метод finalize во всех ваших классах и проверить, когда JVM выходит из основного метода.

  • Если создан только объект C, он должен вызывать finalize для 'C'.
  • Если все объекты A, B, C созданы, он должен вызвать finalize для A, B, C.

Я думаю, что это простейшая проверка, которую вы можете применить.

class A {
    A() {
        //Super(); 
        System.out.println("class A");
    }

    public void finalize(){
    System.out.println("Class A object destroyed");
    }
}
class B extends A {
    B() {
       //Super(); 
        System.out.println("class B");
    }

    public void finalize(){
    System.out.println("Class B object destroyed");
    }
}
class C extends B {
    public static void main(String args[]) {
        C c = new C(); //Parent constructor will get call 
    }

    public void finalize(){
    System.out.println("Class C object destroyed");
    } 
}

Ответ 9

Я согласен с ранее опубликованными ответами, но хочу добавить ссылку на окончательный авторитет по этой проблеме, спецификацию языка Java.

Выражение new C() является выражением создания экземпляра класса. Раздел 15.9.4 Оценка времени выполнения выражений для создания экземпляров класса описывает шаги времени выполнения, связанные с созданием объекта. Обратите внимание, что он ссылается на "объект" и только выделяет пространство один раз, но указывает: "Далее вызывается выбранный конструктор указанного типа класса. Это приводит к вызову хотя бы одного конструктора для каждого суперкласса типа класса".

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

Ответ 10

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

Рассмотрим подкласс Employee, который расширяет свой суперкласс. Person:

public class Employee extends Person{

   public Employee()
   {
     //reference the superclass constructor 
     super(); 
   }

   public String getName()
   {
     //reference superclass behaviors
     return super.getFirstName() + " " + super.getLastName();
   }
 } 

Ключевое слово super может использоваться для ссылки на конструктор класса Person или любого из поведений или полей, к которым у него есть доступ (например, getFirstName() и getLastName()).

Ответ 11

  • В вашем случае Создан один объект

  • при выполнении следующего, этот super() будет предоставлен компилятором неявно

    class A {
    A() {
        System.out.println("class A");
    }
    }
    class B extends A {
    B() {
        System.out.println("class B");
    }
    }
    class C extends B {
    public static void main(String args[]) {
        C c = new C(); //
    }
    }
    

Он похож на вызов super() внутри ваших методов

    B() {
        super();
        System.out.println("class B");
    }

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

super() заставит все конструкторы ссылаться на один класс. (Для легкого понимания: его, как и все функции-члены, входят в один класс). Его вызов будет вызываться только всеми конструкторскими методами.

Таким образом, он выполнил только работу с вызовом конструктора, поэтому super() не будет делать никакого создания объекта. Его просто ссылаются на функции-члены.

Ответ 12

How many number of Object is created in this case.

Когда вы создаете экземпляр класса C с помощью C cInstance = new C();, создается один экземпляр (Object) класса C (Ни один из A и B). Однако, поскольку C extends B и B расширяет A, C будет иметь все методы класса A и B (на самом деле зависит от используемых модификаторов доступа, но позволяет сказать, что для этого случая они общедоступны или по умолчанию).

If one object is created then how internally Super() is calling Parent class Constructor
. How Super is able to call parent class constructor.

Вот как работает наследование. Когда новый объект будет создан, он будет называть его суперклассическим конструктором и суперкласс будет называть его суперклассическим конструктором и т.д. В другой обычной функции вы должны явно вызвать super(). Поэтому вызов конструктора суперкласса происходит снизу вверх, тогда как исполнение идет сверху вниз по дереву иерархии наследования

Ответ 13

Если вы добавите еще одну строку кода System.out.println(this.hashCode()), вы устраните путаницу.

Здесь во всем случае hashCode() будет печатать те же самые hashCode все время. Это означает, что существует один и только один уникальный Object.

class A {
    A() {
        // super(); 
        System.out.println(this.hashCode()); // it will print 2430287
        System.out.println("class A");
    }
}
class B extends A {
    B() {
        // super(); 
        System.out.println(this.hashCode()); // it will print 2430287
        System.out.println("class B");
    }
}
class C extends B {
    public static void main(String args[]) {
        C c = new C(); //Parent constructor will get called
        System.out.println(this.hashCode()); // it will print 2430287
    }
}

но создается два Constructor для инициализации переменной-члена Parent. Я думаю, если вы знаете концепцию ключевого слова super(), которое вызывает конструктор класса Parent и инициализирует член Variable Parent Class.