it-roy-ru.com

Сколько объектов создано из-за наследования в 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 () внутренний объект? Что я знаю, так это то, что конструктор также является методом (я могу ошибаться).

Мои вопросы:

  1. Сколько номеров объектов создано в этом случае?
  2. Если создается один объект, то как Super () внутренне вызывает конструктор родительского класса?
50
Java_begins

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

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

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

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

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

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

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

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

  • Загрузите все ссылочные классы и инициализируйте эти классы. Инициализация класса сама по себе нетривиальна, поэтому я не буду описывать ее здесь. Это стоит прочитать.
  • Выделите часть памяти для хранения элементов экземпляра, которая будет включать все элементы A, B и C.NOTEэто объясняет один аспект вашего вопроса: как конструкторы базового класса и его подклассов могут обновлять или ссылаться на один и тот же объект - все члены экземпляра из всех классов сохраняются по одному после другие в той же части памяти
  • Инициализируйте все элементы к их значению default. Например, члены 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() в качестве первой строки конструктора. Это означает, что конструкторы выполняются строго по порядку:

    1. Object
    2. A
    3. B
    4. 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 во второй фазе инициализации.

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

54
Andrew Alcock

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

Доказательство создания объекта: 

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(). То, что я знаю, это называется родительским конструктором класса. и каждый конструктор Ахве Super() в качестве первого утверждения, как вы упомянули в своем коде. чтобы ты знал

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

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

6
twister_void
  1. Там будет один и только один объект будет создан и т.д. Объект.

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

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

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

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

2
JRR

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

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() just вызывает конструктор of родительский класс и не создает объект

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

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

2
sanbhat
  1. В вашем случае один объект создан

  2. при выполнении следующего, этот 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 () не будет создавать объекты. Это просто ссылка на функции-члены.

1
Pandiyan Cool

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

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

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

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

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

1
Ajay Bhojak

Я не уверен, как полиморфизм/переопределение работает во время 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");
    } 
}
1
Learn More

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

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

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

1
Patricia Shanahan

Если вы посмотрите на динамику размещения объектов в соответствии с ответом this SO, должно быть ясно, что с помощью оператора 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 из aInstance. Таким образом, это ясно доказывает, что на самом деле существует один объект.

1
rahulserver

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

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

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 ()). 

1
Backtrack
How many number of Object is created in this case.

Когда вы создаете экземпляр класса C с помощью C cInstance = new C();, создается один экземпляр (объект) класса C (ни один из A и B). Однако, поскольку C расширяет 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 (). Таким образом, вызов конструктора суперкласса идет снизу вверх, в то время как выполнение идет сверху вниз по иерархии дерева наследования.

1
Aniket Thakur

3 конструктора позвонят

Код:

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

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

class C extends B
{
    C()
    {
        System.out.println("In C");
    }
}

public class InheritanceTest {
    public static void main(String args[])



    {
        C c1=new C();
    }

}

Результат:

В

В б

В С

0
Usman Yaqoob

Если вы добавите еще одну строку кода, функция 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
    }
}

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

0
Vikrant Kashyap