用Java克隆类

时间:2016-11-11 19:52:02

标签: java clone cloneable

我有这个实现Cloneable的类。我这里只需要一份浅色的副本。任何人都可以在这里指出java兼容性有什么问题。

public class EventSystem implements Cloneable{

    private String enrollmentId;
    private String requestId;
    private String tokenId;
    private Date eventAt;
    private Date loggedAt;
    private String appCardId;   
    private String fieldKey;
    private String fieldValue;
    private String trsDimCardIssuerId;
    private String trsDimCardProductId;
    private String trsDimAppEventLocationId;
    private String trsDimPaymentNetworkId;
    private String trsDimAppCardTypeId;
    private String trsTempLogId;



    public Date getEventAt() {
        return eventAt;
    }
    public void setEventAt(Date eventAt) {
        this.eventAt = eventAt;
    }
    public Date getLoggedAt() {
        return loggedAt;
    }
    public void setLoggedAt(Date loggedAt) {
        this.loggedAt = loggedAt;
    }
    public String getRequestId() {
        return requestId;
    }
    public void setRequestId(String requestId) {
        this.requestId = requestId;
    }
    public String getEnrollmentId() {
        return enrollmentId;
    }
    public void setEnrollmentId(String enrollemntId) {
        this.enrollmentId = enrollemntId;
    }
    public String getTokenId() {
        return tokenId;
    }
    public void setTokenId(String tokenId) {
        this.tokenId = tokenId;
    }
    public String getTrsDimCardIssuerId() {
        return trsDimCardIssuerId;
    }
    public void setTrsDimCardIssuerId(String trsDimCardIssuerId) {
        this.trsDimCardIssuerId = trsDimCardIssuerId;
    }
    public String getTrsDimCardProductId() {
        return trsDimCardProductId;
    }
    public void setTrsDimCardProductId(String trsDimCardProductId) {
        this.trsDimCardProductId = trsDimCardProductId;
    }
    public String getTrsDimAppEventLocationId() {
        return trsDimAppEventLocationId;
    }
    public void setTrsDimAppEventLocationId(String trsDimAppEventLocationId) {
        this.trsDimAppEventLocationId = trsDimAppEventLocationId;
    }
    public String getTrsDimPaymentNetworkId() {
        return trsDimPaymentNetworkId;
    }
    public void setTrsDimPaymentNetworkId(String trsDimPaymentNewtorkId) {
        this.trsDimPaymentNetworkId = trsDimPaymentNewtorkId;
    }
    public String getTrsDimAppCardTypeId() {
        return trsDimAppCardTypeId;
    }
    public void setTrsDimAppCardTypeId(String trsDimAppCardTypeId) {
        this.trsDimAppCardTypeId = trsDimAppCardTypeId;
    }
    public static long getSerialversionuid() {
        return serialVersionUID;
    }
     @Override
    public Object clone() throws CloneNotSupportedException {
            return super.clone();
        }
    public String getTrsTempLogId() {
        return trsTempLogId;
    }
    public void setTrsTempLogId(String trsTempLogId) {
        this.trsTempLogId = trsTempLogId;
    }
    public String getAppCardId() {
        return appCardId;
    }
    public void setAppCardId(String appCardId) {
        this.appCardId = appCardId;
    }
    public String getFieldKey() {
        return fieldKey;
    }
    public void setFieldKey(String fieldKey) {
        this.fieldKey = fieldKey;
    }
    public String getFieldValue() {
        return fieldValue;
    }
    public void setFieldValue(String fieldValue) {
        this.fieldValue = fieldValue;
    }
}

此处是否存在String copy问题。

1 个答案:

答案 0 :(得分:1)

您的字符串字段不是问题。您的日期字段是。

当您克隆EventSystem实例时,其每个字段都指向与源对象的相应字段完全相同的对象。因此,克隆实例的enrollmentId字段指向与原始实例的enrollmentId相同的String对象。

但那完全没问题。您可以安全地共享String对象,因为它们是不可变的。无法更改String对象。您可以更改包含String的字段的值,但String对象本身永远不会更改。

但是,可以更改日期对象 。这意味着克隆不是真正独立于源实例。它们都引用相同的可变对象,因此如果只为两个EventSystem实例中的一个更改了该对象,则两个实例都将看到这些更改,这可能会导致一些潜在的错误。请考虑以下代码:

Calendar calendar = Calendar.getInstance();
calendar.set(1969, Calendar.JULY, 20, 22, 56, 0);
Date moonLanding = calendar.getTime();

EventSystem e1 = new EventSystem();
e1.setEventAt(moonLanding);

// Prints Sun Jul 20 22:56:00 EDT 1969
System.out.println(e1.getEventAt());

EventSystem e2 = (EventSystem) e1.clone();

// Both e1 and e2 have references to the same Date object, so changes
// to that Date object are seen in both objects!
e2.getEventAt().setTime(System.currentTimeMillis());

// You might expect these to be different, since we only changed
// e2.getEventAt(), but they're the same.
System.out.println(e1.getEventAt());
System.out.println(e2.getEventAt());

解决此问题的一种方法是使用一种常见的面向对象技术,称为防御性复制:

public Date getEventAt() {
    return (eventAt != null ? (Date) eventAt.clone() : null);
}

public void setEventAt(Date eventAt) {
    this.eventAt = (eventAt != null ? (Date) eventAt.clone() : null);
}

public Date getLoggedAt() {
    return (loggedAt != null ? (Date) loggedAt.clone() : null)
}

public void setLoggedAt(Date loggedAt) {
    this.loggedAt = (loggedAt != null ? (Date) loggedAt.clone() : null);
}

这可以防止任何其他类直接修改内部日期字段。

另一个不太安全的选择是克隆克隆方法中的日期字段:

@Override
public Object clone() throws CloneNotSupportedException {
    EventSystem newInstance = (EventSystem) super.clone();

    if (newInstance.eventAt != null) {
        newInstance.eventAt = (Date) newInstance.eventAt.clone();
    }
    if (newInstance.loggedAt != null) {
        newInstance.loggedAt = (Date) newInstance.loggedAt.clone();
    }

    return newInstance;
}