数据分为基本数据类型和引用数据类型
基本数据类型的:数据直接存储在栈中
引用数据类型的:栈中存储的是一个指针,指向堆中的一块内存,真实的数据存放在堆内存里
对于一般拷贝操作而言,就是把栈中的数据拷贝一份,新数据和源数据一样
所以,对于基本类型,由于数据直接存储在栈中,拷贝一份就意味着把数据拷贝了一份
比如int x = 4
,那么栈中就有一块内存储存了4
,int y = x
就是在栈中新建一个变量(一块内存),并拷贝源数据,即4
,所以此时栈中有两块内存储存的都是4
,一个是x一个是y
所以基本类型默认就是深拷贝
那么,对于基本类型,怎么实现浅拷贝呢?C++在某种意义上实现可以通过指针或引用实现,而Java没有指针,所以并不太好实现,可以参考这里
对于引用类型就不太一样了,string x = "hello"
时,在栈中有一个变量x
,指向堆内存中的hello
string y = x
时,复制栈中的数据,也就是说,y
和x
指向同一块堆内存,这就是浅拷贝,所以java
引用类型默认是浅拷贝
而深拷贝是要在栈中新建一个变量的同时,并且在堆中也新建一块内存,把要复制的值存进去,并将在栈中新建的变量指向堆中新建的内存
即:
浅拷贝:在栈中新建一个变量,还是指向同一块内存
深拷贝:在栈中新建一个变量,并且在堆中也新建一块内存,把要复制的值存进去,将在栈中新建的变量指向堆中新建的内存
那么,既然用=
复制是浅拷贝,怎样能够实现深拷贝呢?
对于数组,当然可以通过.clone()
int[] src = ...
int[] dest = src.clone();
对于class,一种比较安全的方法是先序列化,然后反序列号,可以参考这里
Java中的String类型比较特殊,虽然他是引用类型,但是他具有不可变性,也就是说,在堆内存中的一块String,如"hello"
,内容是不能更改的
string x = "hello"
后,x="world"
会在堆内存中重新划一块内存,储存"world"
,并将x指向新内存,原有内存后续如果没有被引用就会被清理掉
然而,若我们string x = "hello
后string y = x
,y和x指向同一块堆内存"hello"
,但是如上一段所说,x="world"
会在堆中新建一块内存,而不是更改原有内存的数据,也就是说,现在,x指向world,而y依然指向hello
所以对String虽然是引用类型,但是直接使用=
等号,是深拷贝
更详细的证明见这里