java 由于java中的继承,创建了多少个对象?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17877615/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-01 17:52:34  来源:igfitidea点击:

How many objects are created due to inheritance in java?

javaobjectconstructor

提问by Java_begins

Let's say I have three classes:

假设我有三个班级:

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
    }
}

When I create an instance of class C, it calls the constructor of super class. So, is there more than one object that is getting created? If only one object is created, then how is super() like another class' constructor? Does super() method internally create an object? What I know is, the constructor is also a method (I may be wrong).

当我创建类 C 的实例时,它调用超类的构造函数。那么,是否有不止一个对象被创建?如果只创建一个对象,那么 super() 与另一个类的构造函数有何相似之处?super() 方法是否在内部创建对象?我所知道的是,构造函数也是一种方法(我可能错了)。

My questions are:

我的问题是:

  1. How many number of Object is created in this case?
  2. If one object is created then how does Super() internally call the parent class constructor?
  1. 在这种情况下创建了多少个对象?
  2. 如果创建了一个对象,那么 Super() 如何在内部调用父类构造函数?

回答by Andrew Alcock

Great question. What you are probing is how Java initializes objects- and there are a number of steps involved.

很好的问题。您正在探索的是 Java 如何初始化对象- 并且涉及许多步骤。

i know is constructor is also a method (Maybe i am wrong).

我知道构造函数也是一种方法(也许我错了)。

Nearly right. The Constructor is a special method. If you decompile a class file, you'll see the constructors get renamed to <init>. <init>is treated differently from other methods and, for example, can't be called explicitly except through use of the keyword newor super. This is so fundamental that it is implemented in the JVM itself rather than being something defined in the Java language.

几乎正确。构造函数是一种特殊的方法。如果你反编译一个类文件,你会看到构造函数被重命名为<init>. <init>与其他方法的处理方式不同,例如,除非使用关键字newor ,否则不能显式调用super。这是非常基本的,它是在 JVM 本身中实现的,而不是在 Java 语言中定义的东西。

How many number of Object is created in this case.

在这种情况下创建了多少个对象。

One object is created - an instance of C.

创建了一个对象 - 的一个实例C

Cis additionally and simultaneously an instance of Band an instance of Aand also Object.

C是另外地和同时的一个实例B和实例A,并且还Object

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

如果创建了一个对象,那么内部如何super()调用 Parent 类 Constructor 。Super 如何能够调用父类构造函数。

This is where we get into initialization - initialization is how the JVM creates a new instance of an object and sets all the member values - those of the specific class and those of the superclasses. There are several stages involved:

这就是我们进入初始化的地方——初始化是 JVM 创建对象的新实例并设置所有成员值的方式——特定类的值和超类的值。涉及几个阶段:

  • Load all the referenced classes and initialize those classes. Class initialization is itself non-trivial so I won't cover it here. It is well worth reading up.
  • Allocate a chunk of memory for holding the members of the instance, which will include the all members of A, Band C. NOTEthis explains one aspect of your question: how can the constructors of the base class and its subclasses update or refer to the same object - all the members of the instance from all classes are stored one after the other in the same chunk of memory.
  • Initialize all the members to their default value. For example, intand floatmembers will be set to 0 and 0.0f.
  • Execute or calculate the member initializers, eg:

    private int a = 10;
    private int b = a * 5;
    private String c = Singleton.getInstance().getValue();
    
  • Note (1) that member initialization occurs strictly in the order that members are declared in the class. This means that references to members later in the declaration are broken:

    private int a = b * 5; // Forward reference; won't compile
    private int b = 10;
    
  • Note (2) that there is a under-used facility in Java to run arbitrary code to initialize values beforethe constructor is executed. These code blocks are executed at this time again strictly in order of declaration:

    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;
    
  • Execute the constructor of C. Constructors must either directly invoke a constructor from the superclass or the compiler will automatically add super()as the first line of the constructor. This means that the constructors are strictly executed in order:

    1. Object
    2. A
    3. B
    4. C
  • 加载所有引用的类并初始化这些类。类初始化本身很重要,所以我不会在这里介绍。值得一读。
  • 分配一块内存来保存实例的成员,其中将包括AB和的所有成员C注意这解释了您问题的一个方面:基类及其子类的构造函数如何更新或引用同一个对象 -所有类的实例的所有成员都一个接一个地存储在同一块内存中
  • 将所有成员初始化为其默认值。例如,intfloat成员将被设置为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

The object is now initialized and is ready for use. You can do some dangerous stuff if you initialize value using instance methods:

该对象现在已初始化并可使用。如果您使用实例方法初始化值,您可能会做一些危险的事情:

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

Here, ais initialized to 0. This is because, at the point getB()is invoked, Java has cleared the value of bto the default (0), but has not yet set it to 10in the second phase of initialization.

在这里,a被初始化为0。这是因为,在getB()调用点,Java 已将 的值清除为b默认值 ( 0),但尚未10在初始化的第二阶段将其设置为。

In summary - there is only one object and it is created and initialized in a number in stages. During those stages, the object is, by definition, not completely defined.

总而言之 - 只有一个对象,它是在多个阶段中创建和初始化的。在这些阶段,根据定义,对象并没有完全定义。

回答by twister_void

In Code only one object will be created and super call the parent class constructor .

在代码中,只会创建一个对象并超级调用父类构造函数。

Prove of object creation :

对象创建的证明:

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();
    }
}

This will prove that there will be only one object created.

这将证明只会创建一个对象。

And about Super(). What I know that it call Parent class constructor . and each constructor ahve Super()as first statement like you mention in your code . so that you know

而关于Super(). 据我所知,它调用 Parent 类构造函数。并且每个构造函数都Super()作为您在代码中提到的第一个语句。让你知道

I don't know how it internally call super class constructor .

我不知道它内部如何调用超类构造函数。

Hope this will make you understand there is only the instace you create in program

希望这会让你明白只有你在程序中创建的实例

回答by pankaj

  1. There will be one and only one object will be created and ie. A object.

  2. You can imagine like when class A extends B, then all methods and variables are copied to class A.

  1. 将只有一个对象将被创建,即。一个对象。

  2. 你可以想象当类 A 扩展 B 时,然后所有的方法和变量都被复制到类 A 中。

回答by JRR

  1. In your case only, 1 objects is getting created.
  2. When subclasses constructor is called, it calls the constructor of super class internally to initailize super class's members.
  1. 仅在您的情况下,正在创建 1 个对象。
  2. 当子类的构造函数被调用时,它会在内部调用超类的构造函数来初始化超类的成员。

Invoking constructor does not mean you are creating objects. Object is already created when invoking the constructor.The objects is created by the JVM first(i.e memory is allocated on heap and then constructor is called).

调用构造函数并不意味着您正在创建对象。对象在调用构造函数时就已经创建了。对象是由JVM首先创建的(即在堆上分配内存,然后调用构造函数)。

Constructor are meant for initializing the members of objects.

构造函数用于初始化对象的成员。

回答by sanbhat

Your classes will be internally converted to something like this

您的课程将在内部转换为这样的内容

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 
    }
}

How many number of Object is created in this case.

在这种情况下创建了多少个对象。

Only one, which is instance of C, calling super()just invokesthe constructorof parent classand doesn't create object

只有一个,即 的实例C,调用super()只是调用父类构造函数,不创建对象

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

如果创建了一个对象,那么 Super() 在内部如何调用 Parent 类 Constructor 。Super 如何能够调用父类构造函数。

When you create C's instance. C's constructor gets called, which first calls B's constructor, which in turn calls A's constructor

当您创建C的实例时。C的构造函数被调用,它首先调用B的构造函数,然后调用A的构造函数

回答by rahulserver

If you look at dynamics of object allocation as per thisSO answer, it must be clear that using newoperator, you create only one object per statement. To further clarify the doubt that there is only one object which is being created, go thru this program:

如果您按照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);
    }
}

The output:

输出:

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

If you can notice, the super constructor is implicitly getting called each time if a subclass object is created, but since the newoperator is used only once, there is only one object which is actually allocated the space. And by modifying the aInstanceVariablevia Cobject c, we are actually changing the aInstanceVariableof aInstance. So it clearly proves that there is actually one object.

如果您注意到,每次创建子类对象时都会隐式调用超级构造函数,但由于new运算符仅使用一次,因此只有一个对象实际分配了空间。并通过修改aInstanceVariable通过C的对象c,我们实际上是在改变aInstanceVariableaInstance。所以它清楚地证明实际上存在一个对象。

回答by Ajay Bhojak

Steps of object creation when you call a constructor to create object:

调用构造函数创建对象时创建对象的步骤:

  1. Memory allocation using initis done. This init makes a system call to allocate memoryfor object creation.

  2. Then your constructor is called to initialize the object's fields.

  3. Then it calls super class constructor (If there's any super class) and Step 1 through 3 repeats.

  1. 使用init分配内存已完成。这个 init 进行系统调用来为对象创建分配内存

  2. 然后调用您的构造函数来初始化对象的字段。

  3. 然后它调用超类构造函数(如果有任何超类)并重复步骤 1 到 3。

What you see when you decompile a class file using javapshows different calls to be made. initmakes system call to initialize memory allocation but object's field are initialized when constructor's code is run.

使用javap反编译类文件时看到的内容显示了要进行的不同调用。init进行系统调用以初始化内存分配,但在运行构造函数的代码时初始化对象的字段。

回答by Learn More

I am not sure how polymorphism/overriding works at the time of GC.

我不确定多态性/覆盖在 GC 时是如何工作的。

But it should be worth a try to override finalizemethod in all your classes and check when JVM exits main method.

但是应该值得尝试覆盖finalize所有类中的方法并检查 JVM 何时退出 main 方法。

  • If only Cobject is created, it should call finalizefor 'C'.
  • If all A,B, Cobject is created, it should call finalizefor A,B, C.
  • 如果只C创建对象,它应该调用finalize'C'。
  • 如果所有ABC对象被创建,它应该调用finalizeABC

I think this is simplest check you can apply.

我认为这是您可以申请的最简单的检查。

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");
    } 
}

回答by Patricia Shanahan

I agree with the previously posted answers, but want to add a reference to the ultimate authority on this issue, the Java Language Specification.

我同意之前发布的答案,但想添加对此问题的最终权威 Java 语言规范的参考。

The expression new C()is a "Class Instance Creation Expression". Section 15.9.4 Run-time Evaluation of Class Instance Creation Expressionsdescribes the run time steps involved in creating an object. Note that it refers to "the object", and only allocates space once, but states "Next, the selected constructor of the specified class type is invoked. This results in invoking at least one constructor for each superclass of the class type."

该表达式new C()是“类实例创建表达式”。第15.9.4类实例创建表达式的运行时评估描述了创建对象所涉及的运行时步骤。请注意,它指的是“对象”,并且只分配一次空间,但声明“接下来,调用指定类类型的选定构造函数。这导致为类类型的每个超类调用至少一个构造函数。”

This all becomes much clearer by distinguishing between creating a new object, and invoking a constructor. Invoking a constructor only does part of object creation, the part that runs initializers, superclass constructors, and the body of the constructor. Because a C is also a B, the B constructor has to run during creation of a C.

通过区分创建新对象和调用构造函数,这一切变得更加清晰。调用构造函数只执行对象创建的一部分,即运行初始化器、超类构造函数和构造函数主体的部分。因为 C 也是 B,所以 B 构造函数必须在创建 C 期间运行。

回答by backtrack

The super keyword enables a subclass to call the methods and fields of its superclass. It is not an instance of the superclass object but a way to tell the compiler which methods or fields to reference. The effect is the same as if the subclass is calling one of its own methods.Examples:

super 关键字使子类能够调用其超类的方法和字段。它不是超类对象的实例,而是一种告诉编译器要引用哪些方法或字段的方法。效果与子类调用其自己的方法之一相同。例子:

Consider a subclass Employee that extends its superclass Person:

考虑扩展其超类 Person 的子类 Employee:

public class Employee extends Person{

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

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

The super keyword can be used to reference the constructer of the Person class or any of the behaviors or fields that it has access to (e.g., getFirstName() and getLastName()).

super 关键字可用于引用Person 类的构造函数或它有权访问的任何行为或字段(例如,getFirstName() 和getLastName())。