Object
The documentation states that the object needs to be used clone
, and it needs to implement the Cloneable
interface. Cloneable
An interface is just a marker, it doesn't have any methods.
clone
convention
For any object x
,
-return x.clone() != x
as true
-return x.clone().getClass() == x.getClass()
as true
-return x.clone().equals(x)
astrue
But the convention also points out that these are not absolutely necessary
Override clone
method
- For variables with only primitive types or immutable variables in the class,
clone
you can directly call the method of the parent class
public class PhoneNumber implements Cloneable {
private short areaCode;
private short prefix;
private short lineNumber;
public PhoneNumber(int areaCode, int prefix, int lineNumber) {
rangeCheck(areaCode, 999, "area code");
rangeCheck(prefix, 999, "prefix");
rangeCheck(lineNumber, 9999, "line number");
this.areaCode = (short) areaCode;
this.prefix = (short) prefix;
this.lineNumber = (short) lineNumber;
}
private static void rangeCheck(int arg, int max, String name) {
if (arg < 0 || arg > max) {
throw new IllegalArgumentException(name + ": " + arg);
}
}
@Override
public boolean equals(Object o) {
//==判断
if (o == this) {
return true;
}
//instanceof判断
if (!(o instanceof PhoneNumber)) {
return false;
}
//各属性判断
PhoneNumber pn = (PhoneNumber) o;
return pn.lineNumber == lineNumber && pn.prefix == prefix && pn.areaCode == areaCode;
}
@Override
protected PhoneNumber clone() throws CloneNotSupportedException {
return (PhoneNumber) super.clone();
}
}
- For properties in a class that are of reference type, in addition to calling the
clone
method of the parent class, the properties of the reference type also need to be reassigned
public class User implements Cloneable {
private String name;
private int sex;
private String phone;
private Address address;
public User() {
}
public User(String name, int sex, String phone, Address address) {
this.name = name;
this.sex = sex;
this.phone = phone;
this.address = address;
}
@Override
protected Object clone() throws CloneNotSupportedException {
User user = (User) super.clone();
user.address = address.clone();
return user;
}
class Address implements Cloneable {
private String city;
private String area;
private String road;
public Address(String city, String area, String road) {
this.city = city;
this.area = area;
this.road = road;
}
@Override
protected Address clone() throws CloneNotSupportedException {
return (Address)super.clone();
}
}
}
Why use with caution
- As can be seen from the chapter on overriding
clone
methodsclone
, the default method is shallow copy. If deep copy is neededclone
, the re-assignment method needs to be re-assigned to the property, which makes the code look very cumbersome. - The interface represents the methods that customers can call, but the
Cloneable
interface does not have any methods, it only serves as a marker, and the subclass (requires deep copy) modifies the default copy behavior of the parent class
Therefore, in general, methods are rarely used in development clone
. In addition, in the "Alibaba Java Development Manual", there is a suggestion: [Recommendation] Use Object
the clone
method with caution to copy objects. Therefore, in daily development, we should try to avoid clone
the method used .
Alternative method
Commonly replaced methods are:
1. Copy constructor
public class PhoneNumber {
private short areaCode;
private short prefix;
private short lineNumber;
public PhoneNumber(int areaCode, int prefix, int lineNumber) {
rangeCheck(areaCode, 999, "area code");
rangeCheck(prefix, 999, "prefix");
rangeCheck(lineNumber, 9999, "line number");
this.areaCode = (short) areaCode;
this.prefix = (short) prefix;
this.lineNumber = (short) lineNumber;
}
//拷贝构造器
public PhoneNumber(PhoneNumber phoneNumber) {
this.areaCode = phoneNumber.getAreaCode();
this.prefix = phoneNumber.getPrefix();
this.lineNumber = phoneNumber.getLineNumber();
}
private static void rangeCheck(int arg, int max, String name) {
if (arg < 0 || arg > max) {
throw new IllegalArgumentException(name + ": " + arg);
}
}
public short getAreaCode() {
return areaCode;
}
public void setAreaCode(short areaCode) {
this.areaCode = areaCode;
}
public short getPrefix() {
return prefix;
}
public void setPrefix(short prefix) {
this.prefix = prefix;
}
public short getLineNumber() {
return lineNumber;
}
public void setLineNumber(short lineNumber) {
this.lineNumber = lineNumber;
}
}
- copy factory
public class PhoneNumber {
private short areaCode;
private short prefix;
private short lineNumber;
public PhoneNumber(int areaCode, int prefix, int lineNumber) {
rangeCheck(areaCode, 999, "area code");
rangeCheck(prefix, 999, "prefix");
rangeCheck(lineNumber, 9999, "line number");
this.areaCode = (short) areaCode;
this.prefix = (short) prefix;
this.lineNumber = (short) lineNumber;
}
//拷贝工厂方法
public static PhoneNumber newInstance(PhoneNumber phoneNumber) {
return new PhoneNumber(phoneNumber.getAreaCode(), phoneNumber.getPrefix(), phoneNumber.getLineNumber());
}
private static void rangeCheck(int arg, int max, String name) {
if (arg < 0 || arg > max) {
throw new IllegalArgumentException(name + ": " + arg);
}
}
public short getAreaCode() {
return areaCode;
}
public void setAreaCode(short areaCode) {
this.areaCode = areaCode;
}
public short getPrefix() {
return prefix;
}
public void setPrefix(short prefix) {
this.prefix = prefix;
}
public short getLineNumber() {
return lineNumber;
}
public void setLineNumber(short lineNumber) {
this.lineNumber = lineNumber;
}
}