深拷贝 浅拷贝

当我们想复制一个简单类型的数据时:

int a=5;
int b=a;

其他7种简单类型的复制也可以通过这种方式进行。

但当我们想复制一个对象时,就没有这么简单了,

有些初学者复制对象时应该会采用如下方法:

public class Test {
	public static void main(String[] args) {
		Student s1=new Student();
		s1.setStuId(1);
		s1.setStuName("caojie");		
		Student s2=s1;
		System.out.println(s1);
		System.out.println(s2);
	}
}
class Student{
	private int stuId;
	private String stuName;
	public int getStuId() {
		return stuId;
	}
	public void setStuId(int stuId) {
		this.stuId = stuId;
	}
	public String getStuName() {
		return stuName;
	}
	public void setStuName(String stuName) {
		this.stuName = stuName;
	}
	@Override
	public String toString() {
		return "Student [stuId=" + stuId + ", stuName=" + stuName + "]";
	}	
}
如果这样的话,当你改变s2的值得时候,s1的值也会跟着改变,这是因为s2=s1这句话是将s1的引用赋给了s2,两个引用指向同一个内存单元,所以改变其中一个的值,两个对象的值都会发生改变。

那怎样对一个对象进行有效的复制呢?

Object类有一个clone方法,protected native Object clone() throws CloneNotSupportedException,

每个类的直接父类或间接父类都是Object,所以每个类都有clone方法,但这个方法是protected的,类外不能访问,所以每个类必须重写clone方法进行对象的复制。
浅复制:一般 步骤

1.被复制的类需要实现cloneable接口(不实现会抛CloneNotSupportedException异常,该接口是个标记接口,不含任何方法

2.重写clone方法(将访问修饰符改成public,调用super.clone获得需要的复制对象)

修改后的代码是这样的:

class Student implements Cloneable{
	private int stuId;
	private String stuName;
	public int getStuId() {
		return stuId;
	}
	public void setStuId(int stuId) {
		this.stuId = stuId;
	}
	public String getStuName() {
		return stuName;
	}
	public void setStuName(String stuName) {
		this.stuName = stuName;
	}
	
	@Override
	protected Object clone() throws CloneNotSupportedException {
		Student s1=null;
		try{
			s1=(Student)super.clone();//调用super.clone获得需要复制的对象
		}catch (CloneNotSupportedException e) {
			e.printStackTrace();
		}
		return s1;
	}
	
	@Override
	public String toString() {
		return "Student [stuId=" + stuId + ", stuName=" + stuName + "]";
	}	
}
public class Test {
	public static void main(String[] args) throws CloneNotSupportedException {
		Student s1=new Student();
		s1.setStuId(1);
		s1.setStuName("caojie");		
		Student s2=(Student)s1.clone();
		System.out.println(s1);
		System.out.println(s2);
		s2.setStuId(2);
		System.out.println(s1);
		System.out.println(s2);
	}
}
打印结果:

Student [stuId=1, stuName=caojie]
Student [stuId=1, stuName=caojie]
Student [stuId=1, stuName=caojie]
Student [stuId=2, stuName=caojie]
打印System.out.println(s1==s2);输出结果为false

深复制

当我们在Studennt类中加入另一个类的引用,代码如下:

class Student implements Cloneable{
	private int stuId;
	private String stuName;
	private Address addr;	
	public Address getAddr() {
		return addr;
	}
	public void setAddr(Address addr) {
		this.addr = addr;
	}
	public int getStuId() {
		return stuId;
	}
	public void setStuId(int stuId) {
		this.stuId = stuId;
	}
	public String getStuName() {
		return stuName;
	}
	public void setStuName(String stuName) {
		this.stuName = stuName;
	}	
	@Override
	protected Object clone() throws CloneNotSupportedException {
		Student s1=null;
		try{
			s1=(Student)super.clone();//调用super.clone获得需要复制的对象
		}catch (CloneNotSupportedException e) {
			e.printStackTrace();
		}
		return s1;
	}
	@Override
	public String toString() {
		return "Student [stuId=" + stuId + ", stuName=" + stuName + ", addr=" + addr + "]";
	}		
}
class Address{
	private String addr;
	public String getAddr() {
		return addr;
	}
	public void setAddr(String addr) {
		this.addr = addr;
	}
	@Override
	public String toString() {
		return "Address [addr=" + addr + "]";
	}
}
public class Test {
	public static void main(String[] args) throws CloneNotSupportedException {
		Address addr=new Address();
		addr.setAddr("beijjj");
		Student s1=new Student();
		s1.setStuId(1);
		s1.setStuName("caojie");
		s1.setAddr(addr);
		Student s2=(Student)s1.clone();
		System.out.println(s1);
		System.out.println(s2);
		addr.setAddr("haha");
	}
}

打印结果如下:

Student [stuId=1, stuName=caojie, addr=Address [addr=beijjj]]
Student [stuId=1, stuName=caojie, addr=Address [addr=beijjj]]

这样看复制结果是没有任何问题的

当我们改变重新改变地址时:s2.setAddr(addr);

class Student implements Cloneable{
	private int stuId;
	private String stuName;
	private Address addr;	
	public Address getAddr() {
		return addr;
	}
	public void setAddr(Address addr) {
		this.addr = addr;
	}
	public int getStuId() {
		return stuId;
	}
	public void setStuId(int stuId) {
		this.stuId = stuId;
	}
	public String getStuName() {
		return stuName;
	}
	public void setStuName(String stuName) {
		this.stuName = stuName;
	}	
	@Override
	protected Object clone() throws CloneNotSupportedException {
		Student s1=null;
		try{
			s1=(Student)super.clone();//调用super.clone获得需要复制的对象
		}catch (CloneNotSupportedException e) {
			e.printStackTrace();
		}
		return s1;
	}
	@Override
	public String toString() {
		return "Student [stuId=" + stuId + ", stuName=" + stuName + ", addr=" + addr + "]";
	}		
}
class Address{
	private String addr;
	public String getAddr() {
		return addr;
	}
	public void setAddr(String addr) {
		this.addr = addr;
	}
	@Override
	public String toString() {
		return "Address [addr=" + addr + "]";
	}
}
public class Test {
	public static void main(String[] args) throws CloneNotSupportedException {
		Address addr=new Address();
		addr.setAddr("beijjj");
		Student s1=new Student();
		s1.setStuId(1);
		s1.setStuName("caojie");
		s1.setAddr(addr);
		Student s2=(Student)s1.clone();
		System.out.println(s1);
		System.out.println(s2);
		addr.setAddr("haha");
		s2.setAddr(addr);
		System.out.println(s1);
		System.out.println(s2);
	}
}
打印结果如下:

Student [stuId=1, stuName=caojie, addr=Address [addr=beijjj]]
Student [stuId=1, stuName=caojie, addr=Address [addr=beijjj]]
Student [stuId=1, stuName=caojie, addr=Address [addr=haha]]
Student [stuId=1, stuName=caojie, addr=Address [addr=haha]]
可以发现,当我们改变其中一个对象的地址时,两个对象的值都会发生改变

这是因为浅复制只是复制了addr变量的引用,并没有真正的开辟另一块空间,将值复制后再将引用返回给新对象。

所以,为了达到真正的复制对象,而不是纯粹引用复制。我们需要将Address类可复制化,并且修改clone方法,完整代码如下:

class Student implements Cloneable{
	private int stuId;
	private String stuName;
	private Address addr;	
	public Address getAddr() {
		return addr;
	}
	public void setAddr(Address addr) {
		this.addr = addr;
	}
	public int getStuId() {
		return stuId;
	}
	public void setStuId(int stuId) {
		this.stuId = stuId;
	}
	public String getStuName() {
		return stuName;
	}
	public void setStuName(String stuName) {
		this.stuName = stuName;
	}	
	@Override
	protected Object clone() throws CloneNotSupportedException {
		Student s1=null;
		try{
			s1=(Student)super.clone();//调用super.clone获得需要复制的对象
									  //浅复制
		}catch (CloneNotSupportedException e) {
			e.printStackTrace();
		}
		s1.addr=(Address)addr.clone();//深复制
		return s1;
	}
	@Override
	public String toString() {
		return "Student [stuId=" + stuId + ", stuName=" + stuName + ", addr=" + addr + "]";
	}		
}
class Address implements Cloneable{
	private String addr;
	public String getAddr() {
		return addr;
	}
	public void setAddr(String addr) {
		this.addr = addr;
	}
	@Override
	public String toString() {
		return "Address [addr=" + addr + "]";
	}
	@Override
	protected Object clone() throws CloneNotSupportedException {
		Address addr=null;
		addr=(Address)super.clone();
		return addr;
	}
}
public class Test {
	public static void main(String[] args) throws CloneNotSupportedException {
		Address addr=new Address();
		addr.setAddr("beijjj");
		Student s1=new Student();
		s1.setStuId(1);
		s1.setStuName("caojie");
		s1.setAddr(addr);
		Student s2=(Student)s1.clone();
		System.out.println(s1);
		System.out.println(s2);
		addr.setAddr("haha");
		Address addr2=new Address();
		addr2.setAddr("hehe");
		s2.setAddr(addr2);
		System.out.println(s1);
		System.out.println(s2);
	}
}
打印结果:

Student [stuId=1, stuName=caojie, addr=Address [addr=beijjj]]
Student [stuId=1, stuName=caojie, addr=Address [addr=beijjj]]
Student [stuId=1, stuName=caojie, addr=Address [addr=haha]]
Student [stuId=1, stuName=caojie, addr=Address [addr=hehe]]


Java .util.Date: 类也实现了深度复制

public Object clone() {
        Date d = null;
        try {
            d = (Date)super.clone();
            if (cdate != null) {
                d.cdate = (BaseCalendar.Date) cdate.clone();
            }
        } catch (CloneNotSupportedException e) {} // Won't happen
        return d;
    }








  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值