[Effective Java] Carefully override the clone method

ObjectThe documentation states that the object needs to be used clone, and it needs to implement the Cloneableinterface. CloneableAn interface is just a marker, it doesn't have any methods.

cloneconvention

For any object x,
-return x.clone() != xas 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 clonemethod

  1. For variables with only primitive types or immutable variables in the class, cloneyou 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();
  }
}
  1. For properties in a class that are of reference type, in addition to calling the clonemethod 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

  1. As can be seen from the chapter on overriding clonemethodsclone , the default method is shallow copy. If deep copy is needed clone, the re-assignment method needs to be re-assigned to the property, which makes the code look very cumbersome.
  2. The interface represents the methods that customers can call, but the Cloneableinterface 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 Objectthe clonemethod with caution to copy objects. Therefore, in daily development, we should try to avoid clonethe 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;
  }
}
  1. 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;
  }
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325950255&siteId=291194637