Java浅拷贝和深拷贝的区别
浅拷贝和深拷贝的区别
浅拷贝和深拷贝都是复制对象,复制出来的对象,它们的内存地址是重新分配的,修改对象的基本数据类型、包装类型、字符串这些成员变,各对象互不影响。
区别在于
浅拷贝出来的对象,对象中的引⽤类型和原对象中的引⽤类型指向同⼀个内存地址,⽆论修改哪个对象中的引⽤类型,都会影响到另⼀个对象,包括修改引⽤类型中的基本数据类型、包装类型、字符串和引⽤类型,
深拷贝出来的对象,对象中的引⽤类型的内存地址是重新分配的,与原对象的引⽤类型的数据是互不⼲扰。
注意: 浅拷贝和深拷贝的最外层对象的地址⼀定是不同的,最需要的区别是对象中引⽤类型的地址是否相同。基本数据类型及其包装类型、String类型不算引⽤类型!
注意: 再强调⼀次,请区分对象中的基本数据类型及其包装类型、String类型,这些不属于引⽤类型!
特别要注意的是,浅拷贝中,对象中的引⽤类型的地址是同⼀个内存地址,引⽤类型中的基本数据类型及其包装类型、String类型的改变会同步到所有浅拷贝对象及原对象中!
浅拷贝的实现
⽅法⼀:类要实现Cloneable接⼝,重写Object的clone⽅法,在clone⽅法中调⽤super.clone()⽅法即可。
⽅法⼆:只要能实现⼀个对象的所有属性都拷贝到另⼀个新对象的属性中即可,通常使⽤⽅法⼀
public class ShallowCopy implements Cloneable {
public ShallowCopy(){
}
public ShallowCopy(int age, Integer count, String name, Bean bean){
this.age = age;
this.name = name;
this.bean = bean;
}
private int age;
private Integer count;
private String name;
private Bean bean;
@Override
protected Object clone()throws CloneNotSupportedException {
return super.clone();
}
@Override
public String toString(){
return"ShallowCopy hash is "+this.hashCode()+" ,{"+"name="+ name +", count="+ count +", age='"+ age +'\''+", bean="+ bean +"}";
}
}
深拷贝的实现
深拷贝有两种实现⽅式
⽅法⼀:所有⾃定义类都要实现Cloneable接⼝,重写Object的clone⽅法,在对象的clone⽅法中先调⽤⽗类的clone⽅法⽣成当前类的新对象,然后调⽤各个引⽤类型的clone⽅法⽣成各个引⽤类型的新对象,最后把所有引⽤类型的对象设置到当前类的新对象中。
⽅法⼆:通过对象序列化实现深拷贝。所有引⽤类型都要实现Serializable接⼝,各个属性要有setter和getter⽅法,通
过ByteArrayOutputStream、ObjectOutputStream、ByteArrayInputStream和ObjectInputStream完成对象的拷贝。
public class DeepCopy implements Serializable {
public DeepCopy(){
}
public DeepCopy(int age, Integer count, String name, Bean bean){
this.age = age;
this.name = name;
this.bean = bean;
}
private int age;
private Integer count;
private String name;
private Bean bean;
@Override
public String toString(){
return"DeepCopy hash is "+this.hashCode()+" ,{"+"age="+ age +", count="+ count +", name='"+ name +'\''+", bean="+ bean +'}';
}
}
上述代码涉及到的类,所有类的setter和getter都省略了
public class Bean implements Serializable {
public Bean(){
}
public Bean(String clazz,int x, Integer y, SubBean subBean){
this.clazz = clazz;
this.x = x;
this.y = y;
this.subBean = subBean;
}
private String clazz;
private int x;
private Integer y;
private SubBean subBean;
@Overridejava重写和重载的区别
public String toString(){
return"Bean hash is "+this.hashCode()+" ,{"+"clazz='"+ clazz +'\''+", x="+ x +", y="+ y +"} , "+""+"subBean hash is "+ subBean.hashCode(); }
}
public class SubBean implements Serializable {
}
public class Main {
public static void main(String[] args)throws Exception {
print("浅拷贝");
shallow();
print();
print("深拷贝");
deep();
}
public static void print(String title){
System.out.println("*********************"+ title +"*********************");
}
public static void print(){
System.out.println("");
}
public static void deep()throws Exception {
DeepCopy A =new DeepCopy(18,99999,"A",new Bean("三年级",0,99999,new SubBean()));
System.out.String());
ByteArrayOutputStream bos =new ByteArrayOutputStream();
ObjectOutputStream oos =new ObjectOutputStream(bos);
oos.writeObject(A);
oos.flush();
ByteArrayInputStream bis =new ByteArray());
ObjectInputStream ois =new ObjectInputStream(bis);
DeepCopy B =(DeepCopy) adObject();
System.out.String());
}
public static void shallow()throws Exception {
ShallowCopy A =new ShallowCopy(18,99999,"A",new Bean("三年级",0,99999,new SubBean()));
print("观察 A 和 B 对象的 hash");
System.out.String());
ShallowCopy B =(ShallowCopy) A.clone();
System.out.String());
print();
print("修改B对象的基本数据类型/String类型,观察 A 和 B 对象的 hash");
B.setAge(1);
B.setCount(1);
B.setName("B");
System.out.String());
System.out.String());
print();
print("修改C对象的引⽤类型中的数据,观察 A、B 和 C 对象的 hash");
ShallowCopy C =(ShallowCopy) A.clone();
Bean bean = C.getBean();
bean.setX(1111111);
bean.setSubBean(new SubBean());
System.out.String());
System.out.String());
System.out.String());
}
}
测试结果
注意hash值的变化,上述代码中测试了⼏种情况
1. 最外层的对象地址⼀定是不同的
2. 修改B对象的基本数据类型/包装类型/String类型,观察 A 和 B 对象的 hash和数据的变化
3. 修改C对象的引⽤类型中的数据,观察 A、B 和 C 对象的 hash和数据的变化
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论