不可变的子类

时间:2012-07-04 00:27:10

标签: java immutability

我目前正在开发一个多线程框架。为避免副作用,我想要求framewok操纵的所有数据都必须是不可变的。

在Java中是否存在一种方式来指定我希望给定类的所有子类或实现给定接口的所有类都是不可变的?

3 个答案:

答案 0 :(得分:3)

我建议调查Mutability Detector。它执行静态分析以确定给定的类是否是不可变的。它可以用来添加类似于运行时断言的东西,即如果你传递了一个可变类的实例,你可以选择抛出异常。请注意,它可以在运行时分析实际的具体类,包括您定义的接口的子类或实现。

它仍然是1.0之前的版本,并且与java.lang.String存在问题,但它可以使用。如果它接近您正在寻找的东西,但并不完全符合您的要求,我建议您联系邮件列表或提交错误报告,因为我相信项目维护者是一个非常合理的人。免责声明:维护者是我; - )

答案 1 :(得分:2)

无法要求子类的不变性。您可以通过不提供setter并保持实例变量私有来确保类的子类不会改变您的状态,但如果子类声明它们自己的实例变量,则它们可以完全控制它们。

就接口而言,你唯一能做的就是不提供setter。但是,实现可以提供自己的setter。

答案 2 :(得分:1)

为了使一个类真正具有可变性,该类的所有成员必须是不可变的,并且类本身必须是final。这样可以确保无法在类中或类外部更改对象。

要使类中的成员不可变,这意味着不仅仅是使它们成为final。例如

private final List<String> strings = new LinkedList<String>();

stringsfinal但仍可以更改,因为可以在列表中添加和删除项目。在这种情况下,您可以将其包装在不可修改的集合中。即使这样也不完美,因为列表中的对象可能是可变的(Strings显然不是,但是你的列表中可能有可变对象,你可以做list.get(index).mutator(...)

关于如何使对象不可变,没有灵丹妙药。如果它提供了任何改变对象的方法,那么它就不可能是不可变的。

至于制作课程final,以实现保证不变性,这是必要的。想象一下,

class MyImmutableClass {
    private final String name
}

class MutableClass extends MyImmutableClass {
    private String mutableValue;

    public void setMutableValue(String mutableValue...)
}

void doSomething(MyImmutableClass c) {...}

无法保证doSomething实际上正在处理不可变实例,而是可能正在处理可变子类。如您所见,这会对使用接口造成问题。无法保证接口的实现者是不可变的。

@Immutable注释并不能保证不变性,而只是声明该类告诉你它是不可变的,但没有好的方法来强制执行。

如果你能够在groovy中工作,@Immutable注释会产生一些影响,因为它提到了很多这些技术。 http://groovy.codehaus.org/Immutable+AST+Macro