当类A和类B之间存在组合关系时,如下图所示:
在设计的过程中,往往我们会在A类的构造方法中直接实例化B类,我们会认为A类成员对象与B类成员对象之间具有同生共死的生命周期。代码片段如下所示:
class A{
private B b;
public A(){
b = new B();
}
class B{
int x;
}
public static void main(String args[]){
A a = new A();
}
通过上述代码我们能够理解A和B之间的同生关系,但对于其中的共死亡关系,我们又是如何理解的呢?
我们可以从内存结构上来分析,在程序中基本类型的变量如果是临时变量,只要定义了,就会分配内存空间,不管是否被赋值;如果是作为对象的属性出现,只要该对象不实例化,就不会分配内存空间。在上述代码中根据程序的运行,A类的成员变量b因为没有实例化,因此暂时未在内存为其分配空间。当程序从main方法开始运行时,其内存分配如下所示:
(1)首先在栈中分配一个内存空间,该空间存储的是引用变量名称a,当new语句执行时,JVM会在堆内存中分配一个空间来存储A类创建的实例,先按照默认值来初始化对象的各个属性(如A的成员属性b为null),如果没有初始化,那么它的值就是一个默认值,再调用构造函数初始化对象的属性,在构造函数中成员变量b的引用指向堆空间的另一片内存空间,同时把该a实例所在的堆空间的地址传给“a”。
其过程如下图所示:
图一:局部变量a,在还未执行到调用A的构造函数时的内存结构如下图所示:
图二:当执行A a = new A();语句进入到A()构造函数体内语句的执行时,其内存结构如下图所示:
(2)当main方法执行完毕后,被对象a所引用的存放在地址0x112233的对象将会失去引用成为垃圾,等待Java虚拟机进行自动垃圾回收。当a对象被回收后,对象b也同样成为垃圾对象。
如下图所示:
对此当main方法结束,类A的对象a生命周期结束时,类B的对象b声明周期也同时结束。