创建一个没有final字段的不可变对象?

时间:2011-09-21 13:52:05

标签: java oop immutability final

我们可以创建一个不可变对象,而不是所有字段都是最终的吗?

如果可能,有几个例子会有所帮助。

7 个答案:

答案 0 :(得分:6)

声明所有字段为私有且仅定义getter:

public final class Private{
    private int a;
    private int b;

    public int getA(){return this.a;}
    public int getB(){return this.b;}
}

引用@Jon Skeet的评论,最终的类修饰符对以下内容很有用:

  

虽然Just的实例是不可变的,但是一个实例   子类可能是可变的。所以代码接收类型的引用   私人不能依赖它是不可变的而不检查它是不是   只是私人的例子。

因此,如果您想确定您引用的实例是不可变的,那么您还应该使用final final修饰符。

答案 1 :(得分:6)

是的,它是 - 只是确保你的州是私人的,你班上没有任何东西改变它:

public final class Foo
{
    private int x;

    public Foo(int x)
    {
        this.x = x;
    }

    public int getX()
    {
        return x;
    }
}

没有办法在这个类中改变状态,因为它是最终的,你知道没有子类会添加可变状态。

然而:

  • 非最终字段的分配与最终字段的内存可见性规则并不完全相同,因此可能可以从不同的线程中观察“更改”对象。有关最终字段保证的更多详细信息,请参阅section 17.5 of the JLS
  • 如果您不打算更改字段值,我会亲自将其作为文档的最终决定并避免意外添加变更方法
  • 我不记得JVM是否阻止通过反射改变最终字段;显然,任何具有足够权限的调用者都可以使x字段在上面的代码中可访问,并使用反射进行变异。 (根据评论,可以完成最终字段,但结果可能无法预测。)

答案 2 :(得分:3)

术语“不可变”,当用于描述Java对象时,应该意味着线程安全的不变性。如果一个对象是不可变的,通常应该理解任何线程必须遵守相同的状态。

单线程不变性并不是很有趣。如果这是真正提到的,它应该完全符合“单线程”;一个更好的术语是“不可修改的”。

问题是官方提到对“不可变”一词的严格使用。我不能;它基于Java大人物如何使用这个术语。每当他们说“不可变对象”时,他们总是在谈论线程安全的不可变对象。

实现不可变对象的惯用方法是使用final个字段; final语义被专门升级为支持不可变对象。这是一个非常有力的保证;事实上,final字段是唯一的方式; volatile个字段甚至synchronized块无法阻止在构造函数完成之前发布对象引用。

答案 3 :(得分:1)

是的,如果您创建的对象只包含私有成员且没有提供setter,那么它将是不可变的。

答案 4 :(得分:1)

我相信答案是肯定的。

考虑以下对象:

public class point{
   private int x; 
   private int y;
   public point(int x, int y)
   {
      this.x =x; 
      this.y =y;
    }

   public int getX()
    {
       return x;
    }

    public int getY()
    { 
        return y;
    }

}

此对象是不可变的。

答案 5 :(得分:1)

如果类不提供可从外部访问的任何修改对象状态的方法,则该类是不可变的。所以是的,你可以创建一个不可变的类而不使字段最终。例如:

public final class Example {
    private int value;

    public Example(int value) {
        this.value = value;
    }

    public int getValue() {
        return value;
    }
}

但是,没有必要在实际程序中执行此操作,如果您的类应该是不可变的,建议始终将字段设为final。

答案 6 :(得分:0)

是。将字段设为私有。不要在构造函数以外的任何方法中更改它们。当然,既然如此,你为什么不把它们标记为最终的???