一般来说,我是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);
}
}
在舞台后面(我用斜体突出显示了那些引起我最大怀疑的地方:]
obj
的新参考变量NewObject
;new
使用类NewObject
的声明作为蓝图,要求Java提供一些堆内存来分配对象。 new
将Java提供的存储块的地址存储在变量obj
内new
然后在新创建的对象内调用构造函数,并传递两个数值(显式地为3和4),以及该对象的地址(隐式为this
)作为参数。a
和b
,并为其分配从new
接收的值。 构造函数还隐式创建本地this
来存储对象的地址。varA
和varB
,但是没有看到与它们关联的显式this
,因此它首先将它们视为局部变量。由于找不到这些局部变量的相应声明,因此它认为它们必须是实例变量。this
,并且在找到this
时,它将其值用作对象的引用(地址),必须使用其局部变量的值初始化实例变量。 是正确的还是我错过了什么?谢谢!
让我们看一下您主要方法的反编译字节码(我省去了一些不相关的部分:
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
NewObject
invokespecial
通过引用#3调用构造函数。这将从堆栈中获取其必需的参数,并将其从堆栈中弹出(堆栈中的最后3个值是对新对象的引用以及数字3和4)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
引用与其他任何参数一样被对待。
this
加载到堆栈上并调用(对象的超级构造函数)this
,第一个参数a
和第6行将设置字段#2(该对象是varA
对对象引用的this
的引用)的值a
)