如何确定一个类是否是不可变的

Fra*_*fer 11 java oop immutability

在给我的问题具体化之前,让我提供一些背景知识:我的主要编程语言是C++和Java.使用C++时,我发现应用const正确性很重要,即声明这样的函数:

A::DoSomething( const B& arg ); // guarantees that arg is not modified
A::DoSomething() const; // guarantees that the object of type A is not modified
A::DoSomething( const B& arg ) const; // both of the above
Run Code Online (Sandbox Code Playgroud)

事实上,我经常希望这const是默认值,并且必须以某种方式标记被修改的对象.

我使用的主要原因const是:

  • 与其他开发人员的沟通:它使代码更具表现力.
  • 与编译器的通信:它有助于在编译时查找问题,有时可以进行其他优化.

众所周知,Java没有const关键字(你不能做上面的事情final),这个事实在这里已经讨论过,例如参见:Java中的const(C++)的等价物.

通常提出的Java替代方法是使您的类不可变.虽然这不是完全替代,const因为它适用于每个类而不是每个使用类的上下文,但在大多数情况下它对我来说都可以正常工作.

但是不可变类有一个大问题:不可变性并不明显.要知道一个类是否真的是不可变的,据我所知,你基本上必须检查完整的源代码.任何方法都可以有一个后门,通过它可以修改对象.

那么有更简单的方法来检查不变性吗?或者是否有任何最佳实践以某种方式标记一个类是不可变的?

注意:我知道这两种语言都提供了绕过constness或immutability的"邪恶伎俩":C++ const_cast和Java都有反思.但是对于我的问题的背景,我们假设这些都没有被使用.

qww*_*sad 14

Java没有一流的不变性支持,所以你没有可靠的方法来检测类是否是不可变的.

Java Concurrency In Practice建议(参见附录A作为参考)使用类级@Immutable注释javax.annotation.concurrent,这是表示不变性的最方便,最常用和最标准的方法; 自定义javadoc也很好.请注意,它只是声明,而不是实际约束.

班级设计也是一个很好的指标:

  • 只有最终字段(但在极少数情况下,它可能有一些非最终字段并且仍然是不可变的,例如参见String#hashCode)
  • 它构造得恰当(this引用不会从构造函数中泄漏)
  • 无法修改对象状态(因此类不应该有setter和mutator方法)
  • 不要将外部(传递给构造函数)引用存储到可变对象(例如,创建传递的集合参数的防御副本)

可以在Oracle教程中找到不可变类设计属性的完整列表.

因此,要检查类是否是不可变的,首先要查看类级别注释和javadoc,然后才能查看实现本身.

为了提供额外的健全性检查(如果你认为注释为不可变类可能是错误的可变的),FindBugs(静态分析工具)有Mutability Detector插件,它有效地做了上面列出的相同的事情:检查类有@Immutable注释并验证(通过反思)所有不变性规则都得到满足(还有一些额外的东西,比如来自Guava等的不可变收集支持).可变性检测器也可以用作没有FindBugs的库,它允许你编写这样的测试:

@Test
public void testImmutable() {
    assertImmutable(MyClass.class);
}
Run Code Online (Sandbox Code Playgroud)