4

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

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

4

3 回答 3

3

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

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

于 2012-07-04T21:42:22.617 回答
2

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

就接口而言,您唯一能做的就是不提供设置器。但是,实现可以提供自己的设置器。

于 2012-07-04T00:30:01.663 回答
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

于 2012-07-04T22:04:25.433 回答