这是用Java创建新对象的过程的正确描述吗?

问题描述 投票:-1回答:1

一般来说,我是Java和OOP的新手。经过无数次尝试创建新对象的过程之后,我仍然怀疑我是否正确理解内部到底发生了什么(例如“运算符new的作用是什么?”,“谁调用构造函数?”)。 ,“构造函数如何知道要初始化的对象?”“ this是否存在于所有阶段?”等)。

假设我们有一个代码:

class NewObject {
    private int varA;
    private int varB;

    public NewObject(int a, int b) {
        varA = a;
        varB = b;
    }
}

public class Test {
    public static void main(String args[]) {
        NewObject obj = new NewObject(3, 4);
    }
}

在舞台后面(我用斜体突出显示了那些引起我最大怀疑的地方:]

  1. 声明了类obj的新参考变量NewObject
  2. 运算符new使用类NewObject的声明作为蓝图,要求Java提供一些堆内存来分配对象。
  3. 运算符new将Java提供的存储块的地址存储在变量obj
  4. 运算符new然后在新创建的对象内调用构造函数,并传递两个数值(显式地为3和4),以及该对象的地址(隐式为this作为参数。
  5. 在对象内部构造函数创建两个局部变量ab,并为其分配从new接收的值。 构造函数还隐式创建本地this来存储对象的地址。
  6. 构造函数在其主体内部看到了varAvarB,但是没有看到与它们关联的显式this,因此它首先将它们视为局部变量。由于找不到这些局部变量的相应声明,因此它认为它们必须是实例变量。
  7. 因此,构造函数搜索隐式this,并且在找到this时,它将其值用作对象的引用(地址),必须使用其局部变量的值初始化实例变量

是正确的还是我错过了什么?谢谢!

java constructor new-operator
1个回答
0
投票

让我们看一下您主要方法的反编译字节码(我省去了一些不相关的部分:

  public static void main(java.lang.String[]);
    Code:
      stack=4, locals=2, args_size=1
         0: new           #2                  // class NewObject
         3: dup
         4: iconst_3
         5: iconst_4
         6: invokespecial #3                  // Method NewObject."<init>":(II)V
         9: astore_1
        10: return
  • #0表示“分配#2所引用类型的新对象(旁边的注释很好地告诉我们是类NewObject
  • #3表示“复制堆栈上的最新值”(恰好是对新分配的对象的引用)。现在,堆栈包含2个对新对象的引用。
  • #4和#5将数字3和4放在堆栈上
  • #6使用invokespecial通过引用#3调用构造函数。这将从堆栈中获取其必需的参数,并将其从堆栈中弹出(堆栈中的最后3个值是对新对象的引用以及数字3和4)
  • #9将堆栈中的剩余值存储在局部变量#1(这是对新对象的引用)中
  • #10表示main方法已完成,然后返回到称为它的地方。

因此new 字节码仅确保创建了对象的内存,在实际调用构造函数之后,取决于字节码。

请注意,此might意味着您理论上可以创建未初始化的对象并将其传递给您,但是Java运行时在加载的字节码上运行一个称为“验证”的步骤,以验证是否可以进行此类操作永远不会发生(即,您不能只调用new并返回值,运行时将拒绝加载尝试执行此操作的类)。

[如果我们查看NewObject方法的字节码,我们将看到此内容(已删除一些片段):

  public NewObject(int, int);
    Code:
      stack=2, locals=3, args_size=3
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: aload_0
         5: iload_1
         6: putfield      #2                  // Field varA:I
         9: aload_0
        10: iload_2
        11: putfield      #3                  // Field varB:I
        14: return

[请注意,args_size=3告诉我们该方法在堆栈上期望3个值(this和2个实参)。这意味着在此级别,this引用与其他任何参数一样被对待。

  • 在#0和#1行中,我们将this加载到堆栈上并调用(对象的超级构造函数)
  • #4和#5行加载this,第一个参数a和第6行将设置字段#2(该对象是varA对对象引用的this的引用)的值a
  • #9-11行对b所做的相同
  • 第14行标志着构造函数的结尾。
© www.soinside.com 2019 - 2024. All rights reserved.