Java中的对象克隆是指创建一个对象的新实例,新实例与原实例具有相同的状态和行为。这种克隆技术可以通过Java中的clone方法实现,即使用Object类中的clone()方法。clone()方法定义在Object类中,其实现原理主要是通过Object类中的native本地方法实现,将原对象的二进制码流输出,再通过输入流来生成新的对象。但是,它不是一个无条件的克隆,需要考虑深度克隆和浅度克隆两种情况,以及适用场景和使用原则。
1.适用场景:
对象的克隆适用于以下几种场景:
1.1 对象修改时不能影响原有对象:当需要修改对象的某些属性,但是不希望修改原有的对象时,可以使用克隆技术。
1.2 对象的复制:当需要利用已有对象的属性(例如配置项),创建一份新对象并拥有与之相同的属性时,可以使用克隆技术。
1.3 对象的备份:当需要对对象备份并储存到其他地方时,可以使用克隆技术。
2.实现原理:
在Java中,如果对象想要被克隆,需要实现Cloneable接口,并重写clone()方法。Cloneable接口是一个“标记接口”,它没有需要实现的方法。只是用于告诉Object.clone()方法,这个对象是支持复制的。
2.1 实现浅度克隆:
在Java中,如果对象要直接被克隆,使用默认的clone方法即可。对象的clone()方法会直接使用native方法的字节码流来复制一个新的对象,该对象的属性与原对象完全相同,但并不是指向同一内存地址。
Object类的clone()方法是一个protected类型的方法,因此在子类中,它只能使用super.clone()方法来调用父类中的clone方法。通过调用父类的clone()方法,会利用对象中的属性值,生成一个新的对象并返回它。因此,如果一个类要被克隆,它就必须是Cloneable类型的对象,并且需要重写clone()方法,同时需要修改CloneNotSupportedException异常。
public class Person implements Cloneable {
private String name;
private Integer age;
private List
public Person() {}
public Person(String name, Integer age, List
this.name = name;
this.age = age;
this.hobbies = hobbies;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public List
return hobbies;
}
public void setHobbies(List
this.hobbies = hobbies;
}
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
2.2 实现深度克隆:
在Java中,如果对象的引用类型也需要被克隆,则需要进行深度克隆,即递归地克隆引用类型数据。因为对于对象中的引用类型,如果不对它进行克隆的话,复制生成的新对象依然是指向原有的引用类型,不满足深度克隆的要求。
因此,在Java中常常使用一种更为复杂的克隆方式——序列化和反序列化。序列化的方式可以实现对象的深度克隆,同时适用于所有的对象类型,不需要为每一种对象类型都重写clone()方法。
public class Person implements Cloneable, Serializable {
private String name;
private Integer age;
private List
public Person() {}
public Person(String name, Integer age, List
this.name = name;
this.age = age;
this.hobbies = hobbies;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public List
return hobbies;
}
public void setHobbies(List
this.hobbies = hobbies;
}
public Object deepClone() throws IOException, ClassNotFoundException {
//序列化
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
//反序列化
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
Person copy = (Person) ois.readObject();
return copy;
}
}
2.3 使用原则:
在使用对象克隆技术时,需要考虑以下原则:
2.3.1 如果某个对象的成员变量是不可变类型,将其相应的引用拷贝到新对象即可;
2.3.2 如果对象的成员变量指定其他对象,应递归地调用Clone方法,避免新对象与原对象共享句柄;
2.3.3 构造函数可能执行一些动作,但clone方法不会自动地执行这些动作。因此,如果需要在克隆对象时执行特定的动作,需要在重载的clone方法中执行。
总结:
对象克隆技术对于Java语言来说是一个很有用的技术,它可以节省内存资源,提高程序的执行效率,并且能够实现对象的备份,重要数据的恢复等功能。在使用对象克隆技术时,需要根据具体场景选择不同的克隆类型,并需要领会实现原理和使用原则,才能更好地应用在实际开发中。