简体   繁体   English

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

[英]Creating an immutable object without final fields?

Can we create an immutable object without having all fields final? 我们可以创建一个不可变对象,而不是所有字段都是final吗?

If possible a couple of examples would be helpful. 如果可能的话,几个例子会有所帮助。

Declare all fields private and only define getters: 声明所有字段都是私有的,只定义getter:

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

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

citing @Jon Skeet's comment, final class modifier is useful for: 引用@Jon Skeet的评论,最终的类修饰符对以下内容很有用:

While an instance of just Private is immutable, an instance of a subclass may well be mutable. 虽然只是Private的实例是不可变的,但是子类的实例可能是可变的。 So code receiving a reference of type Private can't rely on it being immutable without checking that it's an instance of just Private. 所以接收类型为Private的引用的代码不能依赖它是不可变的而不检查它是否只是Private的实例。

So if you want to be sure the instance you are referring to is immutable you should use also final class modifier. 因此,如果您想确定您所指的实例是不可变的,那么您还应该使用最终的类修饰符。

Yes, it is - just make sure that your state is private, and nothing in your class mutates it: 是的,它是 - 只是确保你的州是私人的,你班上没有任何东西改变它:

public final class Foo
{
    private int x;

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

    public int getX()
    {
        return x;
    }
}

There's no way of mutating the state within this class, and because it's final you know that no subclasses will add mutable state. 在这个类中没有办法改变状态,因为它是最终的,你知道没有子类会添加可变状态。

However: 然而:

  • The assignment of non-final fields doesn't have quite the same memory visibility rules as final fields, so it might be possible to observe the object "changing" from a different thread. 非最终字段的分配与最终字段的内存可见性规则并不完全相同,因此可以从不同的线程中观察对象“更改”。 See section 17.5 of the JLS for more details on the guarantees for final fields. 有关最终字段保证的更多详细信息,请参见JLS的第17.5节
  • If you're not planning on changing the field value, I would personally make it final to document that decision and to avoid accidentally adding a mutating method later 如果您不打算更改字段值,我个人会最终记录该决定并避免以后意外添加变异方法
  • I can't remember offhand whether the JVM prevents mutating final fields via reflection; 我不记得JVM是否阻止通过反射改变最终字段; obviously any caller with sufficient privileges could make the x field accessible in the above code, and mutate it with reflection. 显然,任何具有足够权限的调用者可以在上面的代码中访问x字段,并使用反射对其进行变异。 (According to comments it can be done with final fields, but the results can be unpredictable.) (根据评论,它可以用最终字段完成,但结果可能无法预测。)

The term "immutable", when used to descrbie Java objects, should mean thread-safe immutability. 当用于描述Java对象时,术语“不可变”应该意味着线程安全的不变性。 If an object is immutable, it is generally understood that any thread must observe the same state. 如果一个对象是不可变的,通常应该理解任何线程必须遵守相同的状态。

Single thread immutability is not really interesting. 单线程不变性并不是很有趣。 If that is what really referred to, it should be fully qualified with "single thread"; 如果这是真正提到的,它应该完全符合“单线程”; a better term would be "unmodifiable". 一个更好的术语是“不可修改的”。

The problem is to give an official reference to this strict usage of the term 'immutable'. 问题是官方提到对“不可变”一词的严格使用。 I can't; 我不能; it is based on how Java bigshots use the term. 它基于Java大人物如何使用这个术语。 Whenever they say "immutable object", they are always talking about thread safe immutable objects. 每当他们说“不可变对象”时,他们总是在谈论线程安全的不可变对象。

The idiomatic way to implement immutable objects is to use final fields; 实现不可变对象的惯用方法是使用final字段; final semantics was specifically upgraded to support immutable objects. final语义被专门升级为支持不可变对象。 It is a very strong guarantee; 这是一个非常有力的保证; as a matter of fact, final fields is the only way; 事实上, final领域是唯一的方式; volatile fields or even synchronized block cannot prevent an object reference from being published before constructor is finished. volatile甚至synchronized块都无法阻止在构造函数完成之前发布对象引用。

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

I believe the answer is yes. 我相信答案是肯定的。

consider the following object: 考虑以下对象:

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;
    }

}

This object is immutable. 这个对象是不可变的。

A class is immutable if it does not provide any methods that are accessible from the outside that modify the state of the object. 如果类不提供可从外部访问的任何修改对象状态的方法,则该类是不可变的。 So yes, you can create a class that is immutable without making the fields final. 所以是的,你可以创建一个不可变的类而不使字段最终。 Example: 例:

public final class Example {
    private int value;

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

    public int getValue() {
        return value;
    }
}

However, there is no need to do this in real programs, and it is recommended to always make fields final if your class should be immutable. 但是,没有必要在实际程序中执行此操作,如果您的类应该是不可变的,建议始终将字段设为final。

Yes. 是。 Make the fields private. 将字段设为私有。 Don't change them in any methods other than the constructor. 不要在构造函数以外的任何方法中更改它们。 Of course, that being the case, why wouldn't you label them as final??? 当然,既然如此,你为什么不把它们标记为最终?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM