数据分为基本数据类型引用数据类型

众所周知,(一般)变量是存在栈中的

基本数据类型的变量:数据直接存储在栈中 引用数据类型的变量:栈中存储的是一个指针,指向堆中的一块内存,真实的数据存放在堆内存里

对于一般拷贝操作而言,就是把中的数据拷贝一份,内容和原来一样

基本类型

所以,对于基本类型,由于数据直接存储在栈中,拷贝一份就意味着把数据拷贝了一份

比如int x = 4,那么栈中就有一块内存储存了4int y = x就是在栈中新建一个变量(一块内存),并拷贝源数据,即4

所以此时栈中有两块内存储存的都是4,一个是x一个是y,更改x的值不会影响y,反之同样

所以基本类型默认就是深拷贝

那么,对于基本类型,怎么实现浅拷贝呢?C++在某种意义上实现可以通过指针或引用实现,而Java没有指针,所以并不太好实现,可以参考这里

引用类型

对于引用类型就不太一样了,int[] x = new int[] {1,2}时,在栈中有一个变量x,指向堆内存中的数组

int[] y = x时,复制栈中的数据,也就是说,在栈中新建了一个指针y,和x指向同一块堆内存,也就是刚才的数组

所以此时栈中有两块内存储存的都是指针,一个是x一个是y,但是指向同一块堆内存,更改x的值,如x[1] = 2,y的值也会发生改变

这就是浅拷贝,所以java引用类型默认是浅拷贝

深拷贝是要在栈中新建一个变量的同时,并且在堆中也新建一块内存,把要复制的值存进去,并将在栈中新建的变量指向堆中新建的内存

即: 浅拷贝:在栈中新建一个变量,还是指向同一块内存 深拷贝:在栈中新建一个变量,并且在堆中也新建一块内存,把要复制的值存进去,将在栈中新建的变量指向堆中新建的内存

那么,既然用=复制是浅拷贝,怎样能够实现深拷贝呢?

对于数组,当然可以通过.clone()

int[] src = ...
int[] dest = src.clone();

对于class,一种比较安全的方法是先序列化,然后反序列号,可以参考这里

特殊的 String 类型

Java中的String类型比较特殊,虽然他是引用类型,但是他具有不可变性,也就是说,在堆内存中的一块String,如"hello",内容是不能更改的

string x = "hello"后,再改变x的值:x="world",会在堆内存中重新划一块内存,储存"world",并将x指向新内存,原有内存后续如果没有被引用就会被清理掉(垃圾回收)

然而,若我们string x = "hellostring y = x,y和x指向同一块堆内存"hello",但是如上一段所说,x="world"会在堆中新建一块内存,而不是更改原有内存的数据,也就是说,现在,x指向world,而y依然指向hello

所以对String虽然是引用类型,但是直接使用=等号,是深拷贝

更详细的证明见这里