Java对象之clone方法全面解析
简介
在Java中,如果使用赋值号将一个对象赋值给另外一个对象,那么这两个对象会共用同一份数据。而通过clone()
方法可以创建一个新的对象,并复制原始对象数据到新对象中。
在本篇文章中,我们将全面解析clone()
方法,介绍如何使用clone()
方法拷贝一个Java对象。
clone() 方法说明
clone()
方法是Java中一个被重载的方法,它的主要作用是提供一种克隆方法,用于通过拷贝生成和原始对象完全相同数据的新对象。clone方法并不需要实现Cloneable接口,但是如果不实现的话,在调用clone方法时会抛出CloneNotSupportedException异常。
下面是clone方法的声明:
protected Object clone() throws CloneNotSupportedException
clone方法是一个受保护的方法,因此,只有该类和该类的子类才能访问该方法。如果想要在该类的外部访问该方法,需要在该类的内部定义一个public方法,并在该方法中调用clone方法。
clone的默认行为
通过clone方法,生成了新的对象,但这新的对象和原始对象的数据增加了一份引用。这意味着,如果新对象和原始对象中的某个数据被修改了,那么这两个对象中都会体现出来。
下面是一个例子:
class Person {
String firstName;
String lastName;
}
class MainClass {
public static void main(String args[]) {
Person originalPerson = new Person();
originalPerson.firstName = "Tom";
originalPerson.lastName = "Swift";
Person newPerson = originalPerson.clone();
newPerson.firstName = "John";
System.out.println("Original Person First Name: " + originalPerson.firstName);
System.out.println("New Person First Name: " + newPerson.firstName);
}
}
在这个例子中,我们创建了一个Person对象,并将其赋值给一个引用变量(originalPerson)。然后,我们使用clone()
方法创建了一个新的对象,并将其赋值给一个新的引用变量(newPerson)。我们将新对象的firstName
属性设为John
。我们在输出中查看每个对象的firstName属性值,发现原始对象的firstName属性值没有发生变化,而新的对象的firstName属性被修改了。
通过重写clone方法制定克隆的行为
因为clone方法的默认行为并不总是所期望的,所以你可能需要重写clone()
方法来明确克隆的对象拷贝格式。在默认的情况下,clone()
方法会生成一个新的对象,但是该对象中的数据项还是原来的数据项的引用(这是浅拷贝,shallow copy的一种)。在大多数情况下,这是无法满足需求的。
还是使用上面的Person
类为例,在该类中增加一个address
属性:
class Person {
String firstName;
String lastName;
Address address;
}
class Address {
String street;
String city;
String state;
}
现在尝试通过原始对象拷贝一个新的对象来进行数据的clone操作:
Person originalPerson = new Person();
originalPerson.firstName = "Tom";
originalPerson.lastName = "Swift";
originalPerson.address = new Address();
originalPerson.address.street = "31 Frost St.";
originalPerson.address.city = "New York";
originalPerson.address.state = "NY";
Person newPerson = originalPerson.clone();
newPerson.firstName = "John";
newPerson.address.street = "20 Broadway";
这段代码将会生成一个新的Person对象。因为Address对象中的属性都是引用拷贝,所以结果中,originalPerson对象和newPerson对象中的Address对象的street属性都会被修改,这显然背离了我们希望达到的效果。
在这种情况下,不使用clone方法是更好的选择。应该重写clone方法,将原始对象与新对象进行比较,并在必要时通过深拷贝变得不同。通过实现深拷贝,可以确保新对象中的每个属性都不是原始属性的引用。
下面是一个创建Person方法的示例,其中新对象中的Address属性被深拷贝:
class Person implements Cloneable {
String firstName;
String lastName;
Address address;
protected Object clone() throws CloneNotSupportedException {
Person newPerson = (Person) super.clone();
newPerson.address = (Address) newPerson.address.clone();
return newPerson;
}
}
class Address implements Cloneable {
String street;
String city;
String state;
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
如上所示,当我们在Person
类和Address
类中实现Cloneable
接口时,就可以在深拷贝新对象时使用clone()
方法。在这个示例中,当我们从原始对象进行深拷贝时,将新的Address对象相应地拷贝到新的Person对象中。
下面是一个演示深拷贝的例子:
Person originalPerson = new Person();
originalPerson.firstName = "Tom";
originalPerson.lastName = "Swift";
originalPerson.address = new Address();
originalPerson.address.street = "31 Frost St.";
originalPerson.address.city = "New York";
originalPerson.address.state = "NY";
Person newPerson = originalPerson.clone();
newPerson.firstName = "John";
newPerson.address.street = "20 Broadway";
System.out.println("Original Person Street: " + originalPerson.address.street);
System.out.println("New Person Street: " + newPerson.address.street);
在这个例子中,我们创建了一个Person
对象,并将其赋值给一个引用变量originalPerson。我们还创建了一个新的Person对象,通过调用originalPerson对象的clone()方法来实现深拷贝,将其赋值给新创建的对象。我们修改了新对象的firstName属性,并将新对象的address属性地址设为20 Broadway。我们在输出中查看每个对象的address.street属性值,发现原始对象中的address.street属性值没有发生变化,而新对象的address.street属性被新复制了一份,值变为了20 Broadway,满足了我们的要求。
结论
clone()
方法可以生成两个相同的Java对象,可以根据需要深度或浅拷贝对象。clone方法分为浅拷贝和深拷贝,浅拷贝复制的是引用地址,而深拷贝则是深层次的拷贝所有对象中的属性。
如果你决定在你的Java代码中使用clone()
方法,你应该重写clone()
方法,并遵循在上面提到的建议。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:java object 之clone方法全面解析 - Python技术站