【问题标题】:how Immutable class is created having mutable object as refernce如何使用可变对象作为参考创建不可变类
【发布时间】:2015-07-22 14:53:55
【问题描述】:

我问的是关于“如何在 java 中制作不可变对象”的非常基础的问题。

所以我有一个来自第三方的 Address 类,它不继承任何 Cloneable 接口及其可变类。看起来是这样的

public class Address {

    private String city;
    private String address;

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }
}

现在我有另一个名为 Person 的不可变类,它实现了 Cloneable 接口并覆盖了克隆方法。类看起来像这样

public class Person implements Cloneable {

    private String name;
    private Address address;

    public Person() {

    }

    public Person(String name, Address address) {
        this.name = name;
        this.address = address;
        //this.address = (Address) address.clone();
    }

    public String getName() {
        return name;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Person person = (Person) super.clone();
        return super.clone();
    }

    public Address getAddress() {
        return address;
    }

    @Override
    public String toString() {
        return "name:" + name + ", address" + address.getAddress() + ", city="
                + address.getCity();
    }

}

现在我的问题是,我当然可以克隆 Person 类对象,但如何克隆地址类实例。我还阅读了一些关于浅克隆和深克隆的文章。但我无法理解使用 30 方 API 可以完成多深的克隆。或者,如果我对克隆的理解有误,请纠正我。

【问题讨论】:

  • “实现 Cloneable”不是一个好主意。
  • Address 类非常简单,因此您可以创建自己的类来扩展 Address 并实现 Cloneable。话虽如此,我在这里同意 Raedwald。请看一下这个答案:stackoverflow.com/a/1067437/1011791
  • 注意:您的clone() 方法目前总是返回super.clone()。请改用return person
  • 所以我必须为每个没有实现 Clonable 接口并且可以引用到不可变对象的类编写 Wrapper。这是个好主意吗?
  • 克隆很痛苦。如果可能的话,避免它。你真的需要克隆吗?你想用它做什么?

标签: java


【解决方案1】:

我认为您非常了解:clone 是一个糟糕的机制,实际上有一个完整的错误列表(查看 Effective Java)。与您的情况特别相关,您不能深度克隆具有 final 字段的对象。

改为选择自定义机制来复制对象,例如复制构造函数或专用方法。

内存中的序列化-反序列化循环还有一个技巧,但除非性能和效率在您的列表中不高,否则我不会真正推荐它。

【讨论】:

  • 你是对的。但是如果我写这样的东西。地址地址=新地址(); address.setCity("诺伊达");地址.setAddress("J-75"); Person person = new Person("naveen", address); System.out.println(person.toString()); address.setCity("诺伊达扩展"); System.out.println(person.toString());
  • 那么实际上它破坏了不可变对象的契约。
【解决方案2】:

Cloneable 工具的许多问题之一是,在调用super.clone() 之后,可能有一些字段的状态需要返回并在返回克隆值之前-修复-。这会阻止您在班级中创建这些字段final,并且与不可变班级的原则不一致。此外,该工具可能会在您的类中引入安全漏洞,主要是因为它依赖于语言外的对象创建机制。

一个好的经验法则是如果你可以避免在你的类中实现 Cloneable,那么就避免它。

正如 Marko 所提到的,复制工厂方法的复制构造函数通常是优越的策略,它不依赖于有缺陷的、语言外的对象创建机制。我知道使用clone() 方法的唯一好时机是在获取不可变值数组的防御性副本时,例如原语或Strings

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-05-16
    • 2021-05-04
    • 1970-01-01
    • 2010-09-26
    • 2014-02-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多