对象的克隆

本文详细介绍了Java中的克隆技术,包括实现Cloneable接口、覆盖clone()方法等内容,并通过实例展示了如何实现浅拷贝和深拷贝。

      当你将一个对象的引用作为参数传到一个方法中,而这个方法可能会改变该引用所指对象的属性,但你不想让这种事情发生,此时java的克隆技术能帮到你。下面就来讨论一下,如何让你的类具有可克隆的能力,怎样才能做到深层拷贝。

 

      虽然Object类定义了clone()方法,但并不是每个class天生都具有克隆能力,要想使你的类具有克隆能力,有三件事儿你必须要做:
      1、实现Cloneable接口。
      2、覆盖clone()方法,并把其访问属性改为public的,否则只能在同包中的类或子类中访问,因为Object的clone()方法是protected的。
      3、在clone()方法中调用super.clone()方法。

 

package scjp.cloning;

public class Cloing02 {

	public static void main(String[] args) {
		MyObject obj1 = new MyObject("eric",24);
		MyObject obj2 = null;
		try {
			obj2 = (MyObject)obj1.clone();//obj2是obj1的克隆,此时它们的内容一样,但它们是两个独立的对象。
		} catch (CloneNotSupportedException e) {
			e.printStackTrace();
		}
		//对obj2对象属性的更改不会影响到obj1
		obj2.setAge(25);
		obj2.setName("lth");
		System.out.println(obj1.getName()); //eric
		System.out.println(obj1.getAge()); //24
		System.out.println(obj2.getName()); //lth
		System.out.println(obj2.getAge()); //25
	}
}
class MySuperObject{
	String name;

	public MySuperObject(String name) {
		this.name = name;
	}
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
}
//1、实现Cloneable接口
class MyObject extends MySuperObject implements Cloneable{
	int age;
	
	public MyObject(String name,int age) {
		super(name);
		this.age = age;
	}
	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}
	//2、覆盖clone()方法。
	//如果没有实现Cloneable接口的话,clone()方法会抛出CloneNotSupportedException异常。
	@Override
	public Object clone() throws CloneNotSupportedException {
		return super.clone(); //3、调用super.clone()
	}
}

 

 深层拷贝

 

      上面的例子可以看出,被克隆的类的属性都属于基本类型,所以牵涉不到深层拷贝的问题。但如果被克隆的类是一个组合类(其它类的对象作为成员属性)再用上面的方法就只能做到浅层拷贝即对象成员仍指向本体的对象成员。要想做到深层拷贝需在覆盖clone()方法时下点工夫。

 

package scjp.cloning;

public class Cloning03 {
	public static void main(String[] args) {
		ClassRoom classRoom = new ClassRoom();
		ClassRoom classRoom2 = null;
		try {
			classRoom2 = (ClassRoom)classRoom.clone();
		} catch (CloneNotSupportedException e) {
			e.printStackTrace();
		}
		//更改classRoom2对象的成员属性,不会对classRoom造成影响。
		classRoom2.teacher.name = "Tom";
		for(int i = 0;i < classRoom2.students.length;i++){
			classRoom2.students[i].name = "stu"+i;
			classRoom2.desks[i].hight = 300;
			classRoom2.desks[i].width = 400;
		}
		System.out.println(classRoom);
		System.out.println(classRoom2);
	}
}
class Student implements Cloneable{
	String name;
	public Student(String name) {
		this.name = name;
	}
	@Override
	protected Object clone() throws CloneNotSupportedException {
		return super.clone();
	}
}
class Teacher implements Cloneable{
	String name;
	public Teacher(String name) {
		this.name = name;
	}
	@Override
	protected Object clone() throws CloneNotSupportedException {
		return super.clone();
	}
}
class Desk implements Cloneable{
	int hight;
	int width;
	public Desk(int hight,int width) {
		this.hight = hight;
		this.width = width;
	}
	@Override
	protected Object clone() throws CloneNotSupportedException {
		return super.clone();
	}
}
class ClassRoom implements Cloneable{
	//每个成员都要实现Cloneable接口。
	Teacher teacher; 
	Student[] students;
	Desk[] desks;
	public ClassRoom() {
		this.teacher = new Teacher("Eric");
		this.students = new Student[10];
		this.desks = new Desk[10];
		for(int i = 0;i < this.students.length;i++){
			this.students[i] = new Student("student"+i);
			this.desks[i] = new Desk(200,300);
		}
	}
	@Override
	protected Object clone() throws CloneNotSupportedException {
		ClassRoom classRoom = null;
		classRoom = (ClassRoom)super.clone();
		//每一个成员都要克隆
		classRoom.teacher = (Teacher)classRoom.teacher.clone();
		classRoom.students = classRoom.students.clone();
		classRoom.desks = classRoom.desks.clone();
		//集合中的每一个对象也都要克隆
		for(int i = 0;i < classRoom.students.length;i++){
			classRoom.students[i] = (Student)classRoom.students[i].clone();
			classRoom.desks[i] = (Desk)classRoom.desks[i].clone();
		}
		return classRoom;
	}
	@Override
	public String toString() {
		StringBuilder sbBuilder = new StringBuilder();
		sbBuilder.append("Teacher:").append(this.teacher.name).append("\r\n");
		sbBuilder.append("Students:");
		for(int i = 0;i < this.students.length;i++){
			sbBuilder.append(students[i].name);
			sbBuilder.append(",");
		}
		sbBuilder.append("\r\n");
		sbBuilder.append("Desk(Hight,Width):");
		for(int i = 0;i < this.students.length;i++){
			sbBuilder.append("(");
			sbBuilder.append(desks[i].hight);
			sbBuilder.append(",").append(desks[i].width).append(")");
		}
		sbBuilder.append("\r\n");
		return sbBuilder.toString();
	}
}

 

Teacher:Eric
Students:student0,student1,student2,student3,student4,student5,student6,student7,student8,student9,
Desk(Hight,Width):(200,300)(200,300)(200,300)(200,300)(200,300)(200,300)(200,300)(200,300)(200,300)(200,300)

Teacher:Tom
Students:stu0,stu1,stu2,stu3,stu4,stu5,stu6,stu7,stu8,stu9,
Desk(Hight,Width):(300,400)(300,400)(300,400)(300,400)(300,400)(300,400)(300,400)(300,400)(300,400)(300,400)

 

继承体系中的克隆

 

      默认情况下你自己写的类是不具有克隆能力的,但当你做完了文章开始时所说的三件事后,你的类便拥有了克隆能力,并且继承自该类的所有子类也都与生具有克隆能力。

Java提供了多种对象克隆的方法和实现方式,以下是详细介绍: ### 实现Cloneable接口并重写clone()方法 实现Cloneable接口是Java中实现对象克隆的一种常见方式。需要类实现Cloneable接口,并重写Object类中的clone()方法。示例代码如下: ```java public class User implements Cloneable{ private String username; private String password; public User(String username, String password) { super(); this.username = username; this.password = password; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } @Override public boolean equals(Object obj) { User user = (User) obj; if (username.equals(user.username) && password.equals(user.password)) { return true; } return false; } } ``` 在使用时,可以通过以下方式克隆对象: ```java User user1 = new User("testUser", "testPassword"); try { User user2 = (User) user1.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } ``` ### 通过静态工厂方法实现克隆逻辑 通过静态工厂方法可以集中控制克隆过程。示例代码如下: ```java class Person { private String name; private int age; private Address address; private Person() {} // 私有构造 // 工厂克隆方法 public static Person newInstance(Person other) { Person p = new Person(); p.name = other.name; p.age = other.age; p.address = Address.newInstance(other.address); // 深拷贝 return p; } static class Address { public static Address newInstance(Address other) { Address addr = new Address(); addr.city = other.city; return addr; } } } // 使用示例 Person p2 = Person.newInstance(p1); // 工厂克隆 ``` ### 使用序列化/反序列化(深克隆) 通过对象的序列化和反序列化可以实现深克隆。需要类实现Serializable接口,将对象写入流中,再从流中读取出来,得到的就是一个新的克隆对象。 ### 浅拷贝与深拷贝 浅拷贝只复制对象的基本数据类型和引用类型的引用,而不复制引用类型的对象本身;深拷贝会复制对象的所有属性,包括引用类型的对象本身。在实现深拷贝时,可以使用序列化实现深拷贝、递归克隆实现深拷贝等方法 [^5]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值