关于java:是否先创建了一个对象,然后执行了构造函数?

Is an object created first and then it's constructor executed?

我的问题是

1
A a=new A();

首先创建对象,然后调用构造方法?
还是因为调用了构造函数方法而创建了对象?

如果要求对象调用构造函数,则意味着应该在调用构造函数之前创建对象,并且如果我声明构造函数为私有的(只是看它是否在没有构造函数的情况下工作),那么我得到错误。

现在,如果构造函数执行创建了对象,那么我将无法理解其逻辑上的工作方式,这意味着没有对象,该对象的方法将如何执行?

有人可以解释吗?


是的,在调用构造函数之前,已经为对象分配了内存。

您可以按照以下步骤来考虑:

  • 为对象分配了内存。
  • 执行各种构造函数(总是从层次结构的顶部一直到最具体的构造函数,例如,首先执行Object的构造函数,然后执行您所拥有的其他任何超类,然后执行实际的类)。
  • 因此,该对象已经具有存储空间,并且正在由构造函数初始化,而不是创建它。构造函数只是在设置对象的状态。
  • 在构造函数完成执行之前,该对象不可用。
  • 第4点实际上并不完全正确,因为您可以通过将this传递给构造函数中的另一个方法来泄漏对该对象的引用,但这有点偶然。这是一种令人着迷的现象,因为您可以在变量final初始化之前访问它们,并根据它们在执行的位置从变量中检索两个不同的值。

    解决以下注释:构造函数本身不返回任何内容。它具有void返回类型。变量如何实际接收对象并不像您想象的那么简单,这是一个非常好的问题。您可以在以下Stack Overflow答案中阅读有关此主题的非常详细的答案,这些答案比我在此处可以重复做的要好得多,更彻底。

    • 我们可以为Java中的构造函数提供返回类型吗?
    • 为什么Java中的构造函数没有返回类型?

    作为旁注,正如Peter Lawrey在评论中提到的那样,您可以使用Unsafe API来创建对象的实例,而无需执行构造函数。但是,基于其他一些关于Stack Overflow的讨论,一般的意见似乎是,您使用Unsafe所做的任何事情实际上都不符合正常的Java行为。


    回答C:

    new-expression(假设为new A())的编译方式如下:

    1检查a的默认构造函数在上下文中是否可访问;否则,指示编译错误。

    2a如果类a具有重载的分配函数A::operator new(),则调用它以获得对象的空间。

    2b否则,调用分配函数::operator new()以获得对象的空间。

    3在从分配函数获得的空间中调用默认构造函数A::A()


    您用一种以上的语言标记了问题,您应该选择一种。

    但是惯例是首先为对象及其字段分配内存,然后运行构造函数,然后(如果适用)将对该新对象的引用分配给变量a

    存在一些细微差别。例如,C#对于值类型所做的事情有所不同。

  • 为值类型实例分配内存
  • 运行构造函数
  • 将对象逐位复制到a所指向的位置。
  • 这可确保a永远不要指向值类型的部分构造的实例。它还可以确保,如果构造函数引发异常,则a指向的内存位置不会被破坏。


    构造函数实际上并不创建对象。它们的行为更像是初始化程序。他们将数据设置为JVM赋予它们的对象。


    我总体上同意@dcastro。但是,我相信在这两种语言中,在执行构造函数之前(或至少在构造函数中的代码的第一行之前)都会填充任何行内分配的实例字段。因此,您可以得出以下结论:首先创建对象,然后调用构造函数。

    1
    2
    3
    4
    5
    6
    7
    8
    class MyClass{
        final int value1 = 15;
        final int value2;

        public MyClass(){
              this.value2 = value1;
        }
    }

    在两种语言中,我相信value2将设置为15。因此,将步骤1a - populate in-line instance fields添加到dcastro's答案。


    new运算符通过为新对象分配内存并返回对该内存的引用来实例化一个类。因此,实例化一个类与创建一个对象的含义相同。创建对象时,您正在创建一个类的实例,因此"实例化"了一个类。


    类具有创建对象的构造函数。您在类上而不在对象上调用构造函数,因此总是从类构造函数创建新对象。