引用类型和值类型变量在赋值时的不同
引用类型和值类型变量在赋值时的不同
先讲变量在内存中的存储位置:值类型存储在栈中,引用类型存储在堆中,堆栈这里不明白也不影响,有个基本的概念就行了
先谈复制
int a = 5;
int b = a;
这是值类型,存储在栈中,这个例子中变量b就复制了a,下面看引用类型
Test t1 = new Test();
Test t2 = t1;
这时候t2和t1指向了同一个对象,为什么会这样呢,看看内存中是怎么表示的
第一步int a =5
,先在栈中分配一个空间,假设地址(可以理解为门牌号)是0x00000001,在这个空间中存储了一个值5
第二步int b=a
,这也在栈中分配一个空间,假设地址是0x00000002,因为使用赋值运算符“=”,所以b的空间中存储的值是a的空间中的值的拷贝,这就是值类型的复制
第三步Test t1 = new Test()
,t1是一个引用类型的变量,引用类型的变量在内存中的存储就不一样了,这个语句其实是分两步执行的,首先执行new Test()
,因为使用了new关键字,首先在堆中创建了一块内存空间,我们假设是0x10000001,这时候new Test()
的部分执行完了,然后是将new Test()
的执行结果赋值给Test类型的变量ti,这个过程是在栈中分配空间,假设地址是0x00001001,在这个空间中存储new Test()
返回的堆空间地址。所以,一个引用类型的变量实际是经过了两次跳转的,程序先根据变量名对应的地址找到栈中的空间,再通过栈中空间存储的地址找到堆中的地址空间
明白了这个过程,我们就很好理解为什么当t2=t1
后操作t2时,t1的内容也会跟着变了
第四步Test t2 = t1
,这里只使用了赋值运算符创建了一个变量,所以在内存中的行为仅仅是单纯的在栈中分配一个空间,假设地址是0x00001002,然后将t1在栈中的空间的值拷贝过来,所以t2在栈中的空间存储的也是t1在堆中地址信息
如果调用t2,那么其过程就是根据变量名对应的地址找到栈中的空间,然后栈中空间存储的是从t1那里复制过来的t1指向的堆地址,程序继续跳转到对应的堆地址
t1和t2有不同的栈空间地址,但因为栈空间中存储的堆空间地址相同,经过跳转之后便相当于操作了同一块堆空间,所以无论是t1还是t2对相关内容进行改变,其对应的值都会跟着变