Java中数据类型分为可变类型和不可变类型,前者可以对已经存在的对象进行属性值的修改,而对后者的修改则会直接生成一个达到修改目的的另一个不同的对象,这个特性再一些常见的数据类型操作中会出现一些问题。下面的三个例子是我结合深浅拷贝的一些分析。
java 中拷贝分为深拷贝和浅拷贝,简单理解(并不严谨)就是前者相当于提供了一个别名,后者做出了一个“克隆体”。
在软件构造过程中,为了防止rep exposure,即,表示泄露,常常需要进行防御式拷贝。显然,我们需要的是深拷贝,也就是给外界一个内部结构的克隆体,因而保证内部原有结构不被侵入。
关于深拷贝的关于重写clone(),序列化方法,这里不再赘述。想强调的一点是,不能盲目进行深拷贝,对于一些immutable 的对象,很可能在一些情况下不需要深拷贝也不会导致泄露,这样就省去一些麻烦。
例1:
import java.util.*;
public class TestCopy{
public static void main(String[] args) {
List<String> list = new LinkedList<String>();
list.add("a");
list.add("b");
List<String> listcp = list;
listcp.add("c");
System.out.println(list);//[a,b,c]
System.out.println(listcp);//[a,b,c]
}
}
上面这个显然是傻傻加了个别名,两个名字永远是同步于一个list
例2:
import java.util.*;
public class TestCopy{
public static void main(String[] args) {
List<String> list = new LinkedList<String>();
list.add("a");
list.add("b");
List<String> listcp = new LinkedList<String>(list);
List<String> listcp2 = new LinkedList<String>();
listcp2.addAll(list);
listcp.add("c");
listcp2.add("d");
System.out.println(list);//[a,b]
System.out.println(listcp);//[a,b,c]
System.out.println(listcp2);//[a,b,d]
listcp.set(0, "555");
System.out.println(listcp);//[555,b,c]
}
}
上面两种通过原有list创建新列表的构建方式,对于String这种immutable类型都是稳定的。因为在新列表的修改中,由于String的不可变型,修改时会新建一个字符串,所以,虽然之前 listcp 中的前两位索引指向了与 list 前两位索引相同的地址(“a”,“b” 所在地址),实际使用也并不会产生副作用。
例3:
import java.util.*;
public class TestCopy{
public static void main(String[] args) {
List<stu> list = new LinkedList<stu>();
list.add(new stu(1));
list.add(new stu(2));
List<stu> listcp = new LinkedList<stu>(list);
listcp.add(new stu(3));
System.out.println(list);//[1,2]
System.out.println(listcp);//[1,2,3]
listcp.get(0).set(555);
System.out.println(list);//[555,2]
System.out.println(listcp);//[555,2,3]
}
}
class stu{
int id;
public stu(int id){
this.id = id;
}
public void set(int id){
this.id = id;
}
public int getid(){
return this.id;
}
@Override
public String toString() {
return String.valueOf(this.getid());
}
}
对于一个mutable的类stu,之前的拷贝方式出了问题,如前文所说,因为 listcp 中前两个索引与 list 指向的是同一个空间,又由于对象的可变类型,一个修改就导致另一个发生变化,这显然不是我们希望的。
So ~ 所谓的深拷贝就派上用场,(继承clonable,重写clone(),balabala…扑街问题不再赘述