'new'关键字和构造函数究竟是如何工作的

时间:2014-09-13 01:31:57

标签: java

好的,所以我正在学习我的第一个java认证,我不能完全理解在创建一个对象时底下发生了什么,一些解释说明了这些解释说明构造函数返回对象的引用,这对我来说是一个混乱的根源,因为根据我的理解,这是由new关键字完成的。我的问题是:

  1. 对象的引用实际上来自哪里,' new'关键字还是构造函数?
  2. 使用' new'创建对象时是否隐式将此对象传递给构造函数?
  3. 使用' new'创建对象时关键字,它只是一个java对象,直到它被传递给构造函数,例如。人我=新人();此对象是否在创建后立即与类人关联,或者仅在将其传递给构造函数后

1 个答案:

答案 0 :(得分:0)

  1. new Constructor(arguments)的整个表达式被认为是一个实例创建表达式,并且作为单独的new关键字和构造函数调用没有意义。

    JLS,15.9.4描述了实例的实际创建,它包含三个步骤:

    1. 对表达式进行限定(使用new时不适用)
    2. 在内存中为实例分配空间,并将字段设置为默认值。
    3. 评估构造函数的参数,并调用构造函数。
    4.   

      首先,如果类实例创建表达式是限定类   实例创建表达式,限定主表达式是   评估。如果限定表达式的计算结果为null,则a   引发NullPointerException,并创建类实例   表达突然完成。如果符合条件的表达式完成   突然,类实例创建表达式突然完成   出于同样的原因。

           

      接下来,为新的类实例分配空间。如果有   没有足够的空间来分配对象,评估类   实例创建表达式通过抛出一个突然完成   的OutOfMemoryError。

           

      新对象包含声明的所有字段的新实例   指定的类类型及其所有超类。作为每个新领域   实例创建后,会初始化为默认值(§4.12.5)。

           

      接下来,计算构造函数的实际参数,   左到右。如果任何参数评估突然完成,   不评估其右边的任何参数表达式和类   由于同样的原因,实例创建表达式突然完成。

           

      接下来,调用指定类类型的选定构造函数。   这导致为每个超类调用至少一个构造函数   类类型。这个过程可以通过显式指导   构造函数调用语句(第8.8节)并详细说明   §12.5。

           

      类实例创建表达式的值是对它的引用   新创建的指定类的对象。每一次   在评估表达式时,会创建一个新对象。

    5. 是的,作为字节码,这一切都变成了一个invokespecial调用,新实例位于传递的参数堆栈的底部。请参阅此答案的底部。但是,在语义上,构造函数不会将新实例“传递”给它,但该实例在Java源代码中以this形式提供。

    6. 这个问题没有语义意义,因为在构造函数返回之前,对象不会“存在”外部世界。如果构造突然终止,则实际上不会创建对象并且可用。 然而,至少在OpenJDK JVM的内存中,对象的类型以及它扩展/实现的任何类型都被写入内存头。但是,并非所有实现都能保证这一点。
    7. 拆卸:

      我编译和反汇编:

      class Test{
          public static void main(String args[]){
              Integer s = new Integer(2);
          }
      }
      

      结果如下:

      public static void main(java.lang.String[]);
          Code:
             0: new           #2                  // class java/lang/Integer
             3: dup
             4: iconst_2
             5: invokespecial #3                  // Method java/lang/Integer."<init>":(I)V
             8: astore_1
             9: return
      

      如您所见,首先使用new分配对象,该对象将所有字段填入默认值。它是重复的,所以堆栈看起来像:

      our new Integer
      our new Integer
      

      然后推送我传递给构造函数的常量值:

      2
      our new Integer
      our new Integer
      
      发生

      invokespecial,它传递顶部的两个堆栈元素 - 新实例和构造函数的参数。