大家都知道java里面分为浅拷贝和深拷贝。举个简单的例子,区分一下浅拷贝和深拷贝的区别
public class Address{
private String address;
public Address(String address){
this.address = address;
}
public String getAddress(){
return address;
}
public void setAddress(String address){
this.address = address;
}
@Override
protected Object clone() {
Address address = null;
try {
address = (Address) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return address;
}
}
public class Student implements Cloneable{
private String name;
public List<Address> addressList;
public Student(){
}
public Student(String name) {
this.name = name;
}
public void setName(String name){
this.name = name;
}
public String getName() {
return name;
}
@Override
protected Object clone() {
Student student = null;
try {
student = (Student) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return student;
}
}
先创建两个类,一个是地址,一个是学生,便于后边的打印结果能明显区分浅拷贝和深拷贝。
public class myClass {
public static void main(String[] args) {
Student student = new Student("李晓东");
Student student2 = (Student) student.clone();
println(student.getName() );
println(student2.getName() );
println("改变student2的姓名后--------------");
student2.setName("张天");
println(student.getName() );
println(student2.getName());
}
public static void println(String str) {
System.out.println(str);
}
}
打印结果如下
李晓东
李晓东
改变student2的姓名后--------------
李晓东
张天
可以看到当我们改变student2的name值的时候,并没有改变student的name值(String在此时不属于引用值类型) 在我们的项目当中,经常会遇到一个类里面有List,然后List装载另外一个对象,这个时候要进行深拷贝就需要用到如下的办法,先把Address进行序列化和实现cloneable接口并且重写clone方法。
public class Address implements Cloneable,Serializable{
private String address;
public Address(String address){
this.address = address;
}
public String getAddress(){
return address;
}
public void setAddress(String address){
this.address = address;
}
@Override
protected Object clone() {
Address address = null;
try {
address = (Address) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return address;
}
}
public class myClass {
public static void main(String[] args) {
List<Address> addressList = new ArrayList<>();
addressList.add(new Address("北京市"));
Student student = new Student("李晓东");
student.addressList = addressList;
Student student2 = (Student) student.clone();
student2.addressList = depCopy2(addressList);
println(student.getName() + "---" + student.addressList.get(0).getAddress());
println(student2.getName() + "---" + student2.addressList.get(0).getAddress());
println("改变student2的姓名后--------------");
student2.setName("张天");
student2.addressList.get(0).setAddress("湖南省");
println(student.getName() + "---" + student.addressList.get(0).getAddress());
println(student2.getName() + "---" + student2.addressList.get(0).getAddress());
}
public static void println(String str) {
System.out.println(str);
}
/***
* 方法二
* 需要Address实现cloneable接口和重写clone方法,次方法有限制性,
* 例如要先声明List是保存的什么对象,并且当碰到对象里面还持有List集合的时候
* 就不管用的,所以建议使用第一种方法
*
* @param addresses
* @return
*/
public static List<Address> depCopy2(List<Address> addresses) {
List<Address> destList = new ArrayList<>();
for (Address address : addresses) {
destList.add((Address) address.clone());
}
return destList;
}
/***
* 方法一对集合进行深拷贝 注意需要对泛型类进行序列化(实现Serializable)
*
* @param srcList
* @param <T>
* @return
*/
public static <T> List<T> depCopy(List<T> srcList) {
ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
try {
ObjectOutputStream out = new ObjectOutputStream(byteOut);
out.writeObject(srcList);
ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());
ObjectInputStream inStream = new ObjectInputStream(byteIn);
List<T> destList = (List<T>) inStream.readObject();
return destList;
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
}
此时打印结果是
李晓东---北京市
李晓东---北京市
改变student2的姓名后--------------
李晓东---北京市
张天---湖南省
如果没看明白,可以自己修改不实现cloneable接口和注释掉clone方法再执行看结果,一定要自己写自己试,这样才会印象深刻!!!