【问题标题】:Is an object created first and then it's constructor executed?是先创建一个对象,然后再执行它的构造函数吗?
【发布时间】:2014-08-13 14:01:55
【问题描述】:

我的问题是

A a=new A();

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

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

现在如果构造函数执行创建了对象,我无法理解逻辑上是如何工作的,我的意思是如果没有对象,对象的方法怎么能执行?

谁能解释一下?

【问题讨论】:

  • 我认为这对于询问both C++ 和Java 没有用处
  • 我暂时把 C++ 去掉了,现在来说说 Java

标签: java oop constructor


【解决方案1】:

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

【讨论】:

  • 构造函数不是静态的,如何在类上调用它?
【解决方案2】:

您用不止一种语言标记了问题,您应该选择一种。

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

存在一些细微差别。例如,C# 对值类型的处理方式略有不同。

  1. 为值类型实例分配内存
  2. 运行构造函数
  3. 将对象逐位复制到a 指向的位置。

这确保a 永远不会指向值类型的部分构造实例。它还确保,如果构造函数抛出异常,a 指向的内存位置不会损坏。

【讨论】:

    【解决方案3】:

    回答 C++:

    一个新的表达式(比如new A())编译如下:

    1 检查A 的默认构造函数在上下文中是否可以访问;否则,发出编译错误信号。

    2a 如果类A 有一个重载的分配函数A::operator new(),调用它来为对象获取空间。

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

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

    【讨论】:

      【解决方案4】:

      new 运算符通过为新对象分配内存并返回对该内存的引用来实例化一个类。所以实例化一个类创建一个对象的意思是一样的,当你创建一个对象时,你就是在创建一个类的实例,因此“实例化”一个类。

      【讨论】:

        【解决方案5】:

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

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

        1. 为对象分配内存。
        2. 执行各种构造函数(总是从层次结构的顶部到最具体的构造函数,例如,Object 的构造函数首先执行,然后是您拥有的任何其他超类,然后是实际类的)。
        3. 所以对象已经有内存,它正在由构造函数初始化,而不是创建。构造函数只是设置对象的状态
        4. 在构造函数完成执行之前,该对象不可用。

        第 4 点实际上并不完全正确,因为您可以通过将 this 传递给构造函数中的另一个方法来泄漏对对象的引用,但这有点边缘情况。这是一种令人着迷的现象,因为您可以在 final 变量初始化之前访问它们,并从中检索两个不同的值,具体取决于它们在执行中的位置。

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

        作为旁注,正如 Peter Lawrey 在 cmets 中提到的,您可以使用 Unsafe API 来创建对象的实例,而无需执行构造函数。然而,基于some other Stack Overflow discussions,一般的看法似乎是,您对Unsafe 所做的任何事情都不是真正的正常Java 行为。

        【讨论】:

        • +1 调用 Unsafe.allocateInstance(Class) 允许您在不调用构造函数的情况下创建实例。
        • @PeterLawrey 是的,我想到了这一点,但是根据 Stack Overflow 上的其他一些讨论,人们普遍认为您不应该认为 Unsafe 是该语言的有效使用,因为其中大部分是 @ 987654333@ 代码,它破坏了 JLS。
        • @JeffGohlke 它不是 JLS 的一部分,只是一个库方法。它也不是 JVM 的标准。然而,它确实表明至少对于 HotSpot/OpenJDK,这是一个单独的步骤。
        • 构造函数是否返回对对象的引用?
        • @user2319720 实际上,构造函数本身有一个void 返回类型。这个主题实际上变得有点复杂,并不像你想象的那么简单。您可以将其视为返回对象而不是构造函数的 new 关键字。这里有几个很好的 Stack Overflow Q&A 可能会有所帮助。 stackoverflow.com/a/3501693/1435657stackoverflow.com/a/6801537/1435657
        【解决方案6】:

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

        class MyClass{
            final int value1 = 15;
            final int value2;
        
            public MyClass(){
                  this.value2 = value1;
            }
        }
        

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

        【讨论】:

        • 是的,没错,我没有对整个过程发表评论。它的意义远不止于此。例如,如果这是第一次使用该类,则还必须调用静态构造函数。
        【解决方案7】:

        构造函数实际上并不创建对象。它们更像初始化器。他们将数据设置到 JVM 提供给他们的对象中。

        【讨论】:

          猜你喜欢
          • 2016-04-02
          • 1970-01-01
          • 2021-09-14
          • 1970-01-01
          • 2018-07-06
          • 1970-01-01
          • 1970-01-01
          • 2013-09-30
          • 2020-08-08
          相关资源
          最近更新 更多