浅克隆
浅克隆只会克隆基本数据属性,而不会克隆引用其他对象的属性,String类型除外。(String对象是不可修改的对象,每次修改其实都是新建一个新的对象,而不是在原有的对象上修改,所以当修改String属性时其实是新开辟一个空间存储String对象,并把引用指向该内存,而克隆出来的对象的String属性还是指向原有的内存地址,所以String对象在浅克隆中也表现得与基本属性一样。)
如果你需要拷贝的对象只包含基本数据类型和String直接用浅克隆也没什么影响。
步骤
- 对象的类需要实现Cloneable接口
- 重写Object类中的clone()方法
- 根据重写的clone()方法得到想要的克隆结果
示例:
public class Person implements Cloneable{
private int age ;
private String name;
public Person(int age, String name) {
this.age = age;
this.name = name;
}
public Person() {
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
protected Person clone() throws CloneNotSupportedException {
return (Person) super.clone();
}
}
public static void main(String[] args) throws ClassNotFoundException, CloneNotSupportedException {
Person person = new Person(11,"aa");
Person newPerson = person.clone();
person.setAge(21);
person.setName("bb");
System.out.println(person.toString());
System.out.println(newPerson.toString());
}
深克隆
深克隆会把原型对象和原型对象所引用的对象,都复制一份给克隆对象。原对象和克隆对象完全不搭噶(不搭噶:完全独立,没有关系。)
实现方式
- 实现 Cloneable 接口并重写 Object 类中的 clone()
- 实现 Serializable 接口,通过对象的序列化和反序列化实现克隆
- 通过第三方工具,如Gson、Jackson
优缺点
深拷贝方法 | 优点 | 缺点 |
重写clone()方法 | 1. 底层实现较简单 2. 不需要引入第三方包 3. 系统开销小 | 1. 可用性较差,每次新增成员变量可能需要修改clone()方法 2. 拷贝类(包括其成员变量)需要实现Cloneable接口 |
Apache.Commons.Lang序列化 | 1. 可用性强,新增成员变量不需要修改拷贝方法 | 1. 底层实现较复杂 2. 需要引入Apache Commons Lang第三方JAR包 3. 拷贝类(包括其成员变量)需要实现Serializable接口 4. 序列化与反序列化存在一定的系统开销 |
Gson序列化 | 1. 可用性强,新增成员变量不需要修改拷贝方法 2. 对拷贝类没有要求,不需要实现额外接口和方法 | 1. 底层实现复杂 2. 需要引入Gson第三方JAR包 3. 序列化与反序列化存在一定的系统开销 |
Jackson序列化 | 1. 可用性强,新增成员变量不需要修改拷贝方法 | 1. 底层实现复杂 2. 需要引入Jackson第三方JAR包 3. 拷贝类(包括其成员变量)需要实现默认的无参构造函数 4. 序列化与反序列化存在一定的系统开销 |
public class Attribute implements Cloneable{
//战力值
private int combatPowerValue;
//防御值
private int defenseValue;
public Attribute(int combatPowerValue, int defenseValue) {
this.combatPowerValue = combatPowerValue;
this.defenseValue = defenseValue;
}
public int getCombatPowerValue() {
return combatPowerValue;
}
public void setCombatPowerValue(int combatPowerValue) {
this.combatPowerValue = combatPowerValue;
}
public int getDefenseValue() {
return defenseValue;
}
public void setDefenseValue(int defenseValue) {
this.defenseValue = defenseValue;
}
@Override
public String toString() {
return "Attribute{" +
"combatPowerValue=" + combatPowerValue +
", defenseValue=" + defenseValue +
'}';
}
@Override
protected Attribute clone() throws CloneNotSupportedException {
return (Attribute) super.clone();
}
}
public class Person implements Cloneable{
private int age ;
private String name;
private Attribute attribute;
public Person(int age, String name, Attribute attribute) {
this.age = age;
this.name = name;
this.attribute = attribute;
}
public Person() {
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Attribute getAttribute() {
return attribute;
}
public void setAttribute(Attribute attribute) {
this.attribute = attribute;
}
@Override
protected Person clone() throws CloneNotSupportedException {
Person clone = (Person) super.clone();
//如果有多个引用对象,需要每个对象都需要重新设置,不灵活。
clone.setAttribute(this.attribute.clone());
return clone;
}
@Override
public String toString() {
return "Person{" +
"age=" + age +
", name='" + name + '\'' +
", attribute=" + attribute +
'}';
}
}
public static void main(String[] args) throws ClassNotFoundException, CloneNotSupportedException {
Attribute attribute = new Attribute(1000, 200);
Person person = new Person(11,"aa",attribute);
Person newPerson = person.clone();
person.setAge(21);
person.setName("bb");
person.getAttribute().setCombatPowerValue(500);
System.out.println(person.toString());
System.out.println(newPerson.toString());
}