【问题标题】:Cloning a Class In Java在 Java 中克隆一个类
【发布时间】:2017-03-26 02:40:25
【问题描述】:

我有这个实现 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;
    }
}

这里的字符串复制有问题吗。

【问题讨论】:

  • 它不工作吗?错误是什么?
  • 我很确定文档强烈建议不要在任何情况下使用 clone()。如果你真的需要另一个实例,你可以实现一个复制构造函数。
  • @pathfinderelite - 它工作正常。我唯一的问题是它再次符合 java 规范。但这符合我浅拷贝的目的。
  • 我会说......这看起来像是一个设计问题。 A)一个有这么多领域的类......可能做的事情太多了 B)确定你需要那里的所有那些二传手吗?请注意:您的大多数属性都是字符串。您也可以在这里使用 Map ...但不要误会我的意思:也许您的代码就可以了;但好吧,如果它是我的;我会大幅修改它。
  • 这是一个 DAO 类,它旨在拥有这些。无论如何,问题是,我们在克隆这个方面还有问题吗?

标签: java clone cloneable


【解决方案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;
}

【讨论】:

    猜你喜欢
    • 2017-04-11
    • 1970-01-01
    • 1970-01-01
    • 2013-01-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-26
    • 1970-01-01
    相关资源
    最近更新 更多