关于immutability:如何在JAVA中使返回不可变

How to make the return immutable in JAVA

我有一个物体,比如

1
2
3
4
5
6
7
8
public class ABC {

    private String a;
    private String b;
    private String c;

    //getters and setters    
}

此对象是从集合(如ArrayList中的方法)返回的。

我只想使返回不可变,而不更改对象中的任何内容。有人能帮我吗?


不要提供setter(mutators),将不可变的属性设为private,只通过构造函数提供值赋值。

您总是可以声明不可变的属性final。所以您只能给它们赋值一次,以后不能更改它们。


只使用getter的接口

A是您的具体(impl)类

接口编码?

1
public I getA(){ retrun AImpl();}

哪里

1
2
public interface I { public String getOne()}
public AImple implements I {...}

当前类中唯一的"更改"是"implements i"

JDK和ApacheCommons使用装饰器

http://grepcode.com/file/repository.jboss.org/nexus/content/repository/releases/org.jboss.embedded/thirdparty-all/beta3.sp15/org/apache/commons/collections/list/unmodifiablelist.java

另一个解决方案

克隆您的对象并返回它,这样副本就更改了,原始对象保持不变。


如果对象的类提供了突变,则不能使其不可变。对象始终提供由其类定义的所有功能。

因此,如果您想要一个不可变的对象,那么您需要一个不可变的类。如果您不能更改相关的类,那么像@duffymo这样的包装类就可以达到这个目的。但是,请注意,这样一个类的对象不能与包装类的对象互换,并且您需要以某种方式提供应用包装器。

如果您需要与ABC类的对象完全可互换的对象,那么您必须坚持这样一个事实:ABC是可变的,因此任何与ABC可互换的对象都是可变的,至少在ABC的可变方面是可变的。然后,归根结底就是为什么你想要不变。如果重点是避免改变List引用的对象,那么复制这些对象(到适当的深度)是一种替代方法。

作为第三种选择,如果目标类没有非私有字段,那么您可以创建一个子类,重写setter使其无效,或者抛出一些未经检查的异常。在这种情况下,请注意

  • 这样的子类形式不好,它的实例与ABC类的实例不能真正互换。
  • 如果类abc具有可变类型的可访问属性(例如可变容器),那么您可能还需要做一些事情来防止这些对象发生变化。递归地。
  • 是的,这真是一团糟。