在 Java 中,对象的 clone() 方法提供了一种浅拷贝(shallow copy)对象的方式。浅拷贝会创建一个新对象,新对象与原来的对象共享相同的属性值,但是对象的引用类型成员变量会被拷贝为引用地址(指针)的副本,也就是说,两个对象中的引用类型变量引用的对象是同一个,因此修改其中一个对象的引用类型变量的值,会影响到另外一个对象。由于这个特性,clone() 方法在一些情况下并不适用,例如,当对象中包含有引用类型成员变量的对象时。
clone() 方法定义在 Object 类中,因此所有类都拥有该方法。如果我们想要使用 clone() 方法复制一个对象,我们需要满足以下条件:
- 首先,对象需要实现
Cloneable接口,否则clone()方法会抛出CloneNotSupportedException异常。 - 其次,实现
clone()方法时,需要调用super.clone()方法创建一个原始对象的浅拷贝,然后再复制任何引用类型成员变量的数据。
例如:
public class Person implements Cloneable {
private String name;
private int age;
private Address address;
public Person(String name, int age, Address address) {
this.name = name;
this.age = age;
this.address = address;
}
public String getName() { return name; }
public int getAge() { return age; }
public Address getAddress() { return address; }
public void setName(String name) { this.name = name; }
public void setAge(int age) { this.age = age; }
public void setAddress(Address address) { this.address = address; }
@Override
public Object clone() throws CloneNotSupportedException {
Person clone = (Person) super.clone();
clone.address = (Address) address.clone();
return clone;
}
}
public class Address implements Cloneable {
private String street;
public Address(String street) { this.street = street; }
public String getStreet() { return street; }
public void setStreet(String street) { this.street = street; }
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
在这个例子中,我们自定义了 Person 类和 Address 类,并分别实现了 Cloneable 接口。Person 类中包含了一个 Address 类型的属性 address。在 Person 类中重写 clone() 方法时,我们先调用 super.clone() 方法创建一个浅拷贝的对象 clone,然后再将 address 属性单独进行克隆,从而实现深拷贝。
现在我们可以创建一个 Person 对象并克隆它。例如:
Address address = new Address("123 Main St");
Person person1 = new Person("Tom", 18, address);
Person person2 = (Person) person1.clone();
System.out.println(person1.getAddress().getStreet()); // 123 Main St
System.out.println(person2.getAddress().getStreet()); // 123 Main St
address.setStreet("456 Main St");
System.out.println(person1.getAddress().getStreet()); // 456 Main St
System.out.println(person2.getAddress().getStreet()); // 123 Main St
在这个例子中,我们先创建了一个 Person 对象 person1,然后克隆它得到了一个新的对象 person2。person1 和 person2 的 address 引用类型成员变量共享同一个对象。当我们修改 address 对象的值时,会影响到 person1 和 person2 的 address 引用类型变量的值。因此,person2.getAddress().getStreet() 输出 “123 Main St”,而不是 “456 Main St”。
需要注意的是,
clone()方法并不是一个通用方案,它需要在适当的情况下使用,因为克隆方法可能会导致难以诊断的性能问题。例如,在需要复制的对象非常大的情况下,使用clone()方法可能会导致大量的内存开销,因为它需要在堆上为复制数据创建新的对象。在这种情况下,我们可能需要使用其他的方式来复制对象,例如序列化和反序列化,或者手动实现复制方法。因此,在使用clone()方法时,需要根据具体的场景和需求谨慎选择,并考虑其可能带来的性能问题。
深克隆和浅克隆都是对象复制的方式。
浅克隆(Shallow Copy)是一种对象复制的方式,它只复制对象的基本类型属性和引用类型属性的地址,而不是开辟新的内存空间重新分配引用类型成员变量引用的对象。即两个对象指向相同的引用类型成员变量引用的对象。例如,假设一个对象 A 包含一个引用类型成员变量 B,复制该对象时,只会复制该对象本身以及 B 对象的地址,而不会再复制 B 所引用的对象。
深克隆(Deep Copy)是一种对象复制的方式,它会完全复制一个对象及其所有的引用类型成员变量引用的对象,即为各自复制分配了新的内存空间,不再是单纯的地址复制。即两个对象都拥有自己的引用类型成员变量引用的对象。
实现深克隆,需要手动实现复制方法,例如通过重写 clone() 方法来实现。在实现深克隆的过程中,需要保证每个拥有引用类型成员变量的对象都能够被正确地拷贝,避免两个对象共享同一引用类型成员变量。
在 Java 中,clone() 方法提供的是浅克隆。如果我们需要深克隆,必须要手动实现复制的方法。
需要注意的是,在选择使用哪种方式进行对象复制时,应该根据具体的场景和需求进行选择。如果对象中包含的成员变量较多,且其中包含了较多的引用类型成员变量,那么建议使用深克隆。但是,需要注意的是,在创建新的对象并拷贝所有引用类型成员变量时,也可能引起性能问题。如果对象中包含的成员变量都是基本类型数据或不可变类型,那么建议使用浅克隆,以减少不必要的复制开销。