Java 不可变类?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3162665/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 16:59:16  来源:igfitidea点击:

Immutable class?

javastringimmutability

提问by JavaUser

How can one make a Java class immutable, what is the need of immutability and is there any advantage to using this?

如何使 Java 类不可变,什么是不可变性的需要,使用它有什么好处?

采纳答案by coobird

What is an immutable object?

什么是不可变对象?

An immutable object is one that will not change state after it is instantiated.

不可变对象是一种在实例化后不会改变状态的对象。

How to make an object immutable?

如何使对象不可变?

In general, an immutable object can be made by defining a class which does not have any of its members exposed, and does not have any setters.

一般来说,不可变对象可以通过定义一个没有暴露任何成员并且没有任何 setter 的类来创建。

The following class will create an immutable object:

以下类将创建一个不可变对象:

class ImmutableInt {
  private final int value;

  public ImmutableInt(int i) {
    value = i;
  }

  public int getValue() {
    return value;
  }
}

As can be seen in the above example, the value of the ImmutableIntcan only be set when the object is instantiated, and by having only a getter (getValue) the object's state cannot be changed after instantiation.

从上面的例子中可以看出,对象的值ImmutableInt只能在实例化时设置,并且只有一个getter( getValue),对象的状态在实例化后是无法改变的。

However, there must be care taken that all objects that are referenced by the object must be immutable as well, or it could be possible to change the state of the object.

但是,必须注意对象引用的所有对象也必须是不可变的,否则可能会更改对象的状态。

For example, allowing an reference to an array or ArrayListto be obtained through an getter will allow the internal state to change by changing the array or collection:

例如,允许对数组的引用或ArrayList通过 getter 获取将允许通过更改数组或集合来更改内部状态:

class NotQuiteImmutableList<T> {
  private final List<T> list;

  public NotQuiteImmutableList(List<T> list) {
    // creates a new ArrayList and keeps a reference to it.
    this.list = new ArrayList(list); 
  }

  public List<T> getList() {
    return list;
  }
}

The problem with the above code is, that the ArrayListcan be obtained through getListand be manipulated, leading to the state of the object itself to be altered, therefore, not immutable.

上面代码的问题是,ArrayList可以通过获取getList和操作,导致对象本身的状态被改变,因此不是一成不变的。

// notQuiteImmutableList contains "a", "b", "c"
List<String> notQuiteImmutableList= new NotQuiteImmutableList(Arrays.asList("a", "b", "c"));

// now the list contains "a", "b", "c", "d" -- this list is mutable.
notQuiteImmutableList.getList().add("d");

One way to get around this problem is to return a copy of an array or collection when called from a getter:

解决此问题的一种方法是在从 getter 调用时返回数组或集合的副本:

public List<T> getList() {
  // return a copy of the list so the internal state cannot be altered
  return new ArrayList(list);
}

What is the advantage of immutability?

不变性有什么好处?

The advantage of immutability comes with concurrency. It is difficult to maintain correctness in mutable objects, as multiple threads could be trying to change the state of the same object, leading to some threads seeing a different state of the same object, depending on the timing of the reads and writes to the said object.

不变性的优势来自于并发。在可变对象中很难保持正确性,因为多个线程可能会尝试更改同一对象的状态,导致某些线程看到同一对象的不同状态,具体取决于对所述对象的读取和写入时间目的。

By having an immutable object, one can ensure that all threads that are looking at the object will be seeing the same state, as the state of an immutable object will not change.

通过拥有一个不可变对象,可以确保所有正在查看该对象的线程都将看到相同的状态,因为不可变对象的状态不会改变。

回答by duffymo

You make a class immutable like this:

您可以像这样使类不可变:

public final class Immutable
{
    private final String name;

    public Immutable(String name) 
    {
        this.name = name;
    }

    public String getName() { return this.name; } 

    // No setter;
}

Following are the requirements to make a Java class immutable:

以下是使 Java 类不可变的要求:

  • Classmust be declared as final(So that child classes can't be created)
  • Membersin the class must be declared as final(So that we can't change the value of it after object creation)
  • Write Getter methodsfor all the variables in it to get Membersvalues
  • No Setters methods
  • 必须声明为final(以便无法创建子类)
  • 类中的成员必须声明为final(这样我们就不能在创建对象后更改它的值)
  • 为其中的所有变量编写Getter方法以获取Members
  • 没有 Setter 方法

Immutable classes are useful because
- They're thread-safe.
- They also express something deep about your design: "Can't change this.", When it applies, it's exactly what you need.

不可变类很有用,因为
- 它们是线程安全的。
- 他们还表达了一些关于您的设计的深刻内容:“无法改变这一点。”,当它适用时,这正是您所需要的。

回答by Hyman

Immutability can be achieved mainly in two ways:

不变性主要可以通过两种方式实现:

  • using finalinstance attributes to avoid reassignment
  • using a class interface that simply doesn't allow any operation that is able to modify what is inside your class (just gettersand no setters
  • 使用final实例属性避免重新分配
  • 使用一个类接口,它根本不允许任何能够修改类中内容的操作(只有getter没有setter

Advantages of immutability are the assumptions that you can make on these object:

不变性的优点是您可以对这些对象做出的假设:

  • you gain the no-side effect rule (that is really popular on functional programming languages) and allows you to use objects in a concurrent environment easier, since you know that they can't be changed in a atomic or non atomic way when they are used by many threads
  • implementations of languages can treat these objects in a different way, placing them in zones of memory that are used for static data, enabling faster and safer use of these objects (this is what happens inside the JVM for strings)
  • 您获得了无副作用规则(这在函数式编程语言中非常流行)并允许您更轻松地在并发环境中使用对象,因为您知道它们不能以原子或非原子方式更改时被多个线程使用
  • 语言的实现可以以不同的方式处理这些对象,将它们放置在用于静态数据的内存区域中,从而更快、更安全地使用这些对象(这就是在 JVM 内部发生的字符串)

回答by Fabian Steeg

In addition to the answers already given, I'd recommend reading about immutability in Effective Java, 2nd Ed., as there are some details that are easy to miss (e.g. defensive copies). Plus, Effective Java 2nd Ed. is a must-read for every Java developer.

除了已经给出的答案之外,我建议您阅读 Effective Java, 2nd Ed. 中关于不变性的内容,因为有一些很容易遗漏的细节(例如防御性副本)。另外,Effective Java 第二版。是每个 Java 开发人员的必读之书。

回答by Kandy

Immutable classes cannot reassign values after it is instantiated.The constructor assign values to its private variables. Until the object becomes null, values cannot be changed due to unavailability of setter methods.

不可变类在实例化后不能重新赋值。构造函数为其私有变量赋值。在对象变为 null 之前,由于 setter 方法不可用,无法更改值。

to be immutable should satisfy following,

不可变应满足以下条件,

  • Al the variables should be private.
  • No mutatormethods(setters) are provided.
  • Avoid method overriding by making class final(Strong Immutability) or methods final(Week immutability).
  • Clone deeply if it contain non primitive or mutable classes.
  • Al 变量应该是private
  • 没有提供增变方法(setter)。
  • 通过使类最终(强不变性)或方法最终(周不变性)来避免方法覆盖。
  • 如果它包含非原始类或可变类,则进行深度克隆。


/**
* Strong immutability - by making class final
*/
public final class TestImmutablity {

// make the variables private
private String Name;

//assign value when the object created
public TestImmutablity(String name) {
this.Name = name;
}

//provide getters to access values
public String getName() {

return this.Name;
}
}

Advanteges: Immutable objects contains its initialized values until it dies.

优点:不可变对象包含它的初始化值,直到它死亡。

java-immutable-classes-short-note

java-immutable-classes-short-note

回答by Yasir Shabbir Choudhary

Immutable classare those whose objects cannot be changed after creation.

不可变类是那些对象在创建后无法更改的类。

Immutable classes is useful for

不可变类对于

  • Caching purpose
  • Concurrent environment (ThreadSafe)
  • Hard for inheritance
  • Value cannot be changed in any environment
  • 缓存目的
  • 并发环境(ThreadSafe)
  • 难以继承
  • 在任何环境中都不能更改值

Example

例子

String Class

字符串类

Code Example

代码示例

public final class Student {
    private final String name;
    private final String rollNumber;

    public Student(String name, String rollNumber) {
        this.name = name;
        this.rollNumber = rollNumber;
    }

    public String getName() {
        return this.name;
    }

    public String getRollNumber() {
        return this.rollNumber;
    }
}

回答by Justas

Another way to make immutable object is using Immutables.orglibrary:

制作不可变对象的另一种方法是使用Immutables.org库:

Assuming that required dependencies were added, create an abstract class with abstract accessor methods. You can do the same by annotating with interfaces or even annotations (@interface):

假设添加了所需的依赖项,创建一个带有抽象访问器方法的抽象类。您可以通过使用接口甚至注释(@interface)进行注释来执行相同的操作:

package info.sample;

import java.util.List;
import java.util.Set;
import org.immutables.value.Value;

@Value.Immutable
public abstract class FoobarValue {
  public abstract int foo();
  public abstract String bar();
  public abstract List<Integer> buz();
  public abstract Set<Long> crux();
}

It is now possible to generate and then use the generated immutable implementation:

现在可以生成然后使用生成的不可变实现:

package info.sample;

import java.util.List;

public class FoobarValueMain {
  public static void main(String... args) {
    FoobarValue value = ImmutableFoobarValue.builder()
        .foo(2)
        .bar("Bar")
        .addBuz(1, 3, 4)
        .build(); // FoobarValue{foo=2, bar=Bar, buz=[1, 3, 4], crux={}}

    int foo = value.foo(); // 2

    List<Integer> buz = value.buz(); // ImmutableList.of(1, 3, 4)
  }
}

回答by bbgw

As a non-native English speaker, I dislike the common interpretation of "immutable class" being "constructed class objects are immutable"; rather, I myself lean to interpret that as "the class object itself is immutable".

作为非英语母语人士,我不喜欢“不可变类”的常见解释是“构造的类对象是不可变的”;相反,我自己倾向于将其解释为“类对象本身是不可变的”。

That said, "immutable class" is a kind of immutable object. The difference is when answering what the benefit is. To my knowledge/interpretation, immutable class prevents its objects from runtime behavior modifications.

也就是说,“不可变类”是一种不可变对象。区别在于回答好处是什么时。据我所知/解释,不可变类防止其对象运行时行为修改。

回答by sandeep vanama

An immutable class is simply a class whose instances cannot be modified.

不可变类只是一个实例不能修改的类。

All ofthe information contained in each instance is fixed for the lifetime of the object, so no changes can ever be observed.

每个实例中包含的所有信息在对象的生命周期内都是固定的,因此无法观察到任何变化。

Immutable classes are easier to design, implement, and use than mutable classes.

不可变类比可变类更容易设计、实现和使用。

To make a class immutable, follow these five rules:

要使类不可变,请遵循以下五个规则:

  1. Don't provide methods that modify the object's state

  2. Ensure that the class can't be extended.

  3. Make all fields final.

  4. Make all fields private.

  5. Ensure exclusive access to any mutable components.

  1. 不要提供修改对象状态的方法

  2. 确保该类无法扩展。

  3. 使所有字段最终。

  4. 将所有字段设为私有。

  5. 确保对任何可变组件的独占访问。

Immutable objects are inherently thread-safe; they require no synchronization.

不可变对象本质上是线程安全的;它们不需要同步。

Immutable objects can be shared freely.

不可变对象可以自由共享。

Immutable objects make great building blocks for other objects

不可变对象为其他对象提供了很好的构建块

回答by Srikant M

Most of the answers here are good, and some mentioned the rules but I feel its good to put down in words why& when we need to follow these rules. So am giving the below explanation

这里的大多数答案都很好,有些人提到了规则,但是当我们需要遵循这些规则时,我觉得用文字解释为什么和这样很好。所以我给出以下解释

  • Declare the member variables as ‘final' – When we declare them as final , compiler forces us to initialize them. We can initialize directly, by default constructor, by arg constructor.( see sample code below) and after initialization we cannot modify them as they are final.
  • And of course if we try to use Setters for those final variables, compiler throws error.

    public class ImmutableClassExplored {
    
        public final int a; 
        public final int b;
    
        /* OR  
        Generally we declare all properties as private, but declaring them as public 
        will not cause any issues in our scenario if we make them final     
        public final int a = 109;
        public final int b = 189;
    
         */
        ImmutableClassExplored(){
            this. a = 111;
            this.b = 222;
        }
    
        ImmutableClassExplored(int a, int b){
            this.a = a;
            this.b= b;
        }
    }
    
  • 将成员变量声明为“final”——当我们将它们声明为 final 时,编译器会强制我们初始化它们。我们可以直接初始化,默认构造函数,通过 arg 构造函数。(见下面的示例代码),初始化后我们不能修改它们,因为它们是最终的。
  • 当然,如果我们尝试对这些最终变量使用 Setter,编译器会抛出错误。

    public class ImmutableClassExplored {
    
        public final int a; 
        public final int b;
    
        /* OR  
        Generally we declare all properties as private, but declaring them as public 
        will not cause any issues in our scenario if we make them final     
        public final int a = 109;
        public final int b = 189;
    
         */
        ImmutableClassExplored(){
            this. a = 111;
            this.b = 222;
        }
    
        ImmutableClassExplored(int a, int b){
            this.a = a;
            this.b= b;
        }
    }
    

Do we need to declare class as ‘final'?

我们是否需要将类声明为“final”?

  • Without final keyword in class declaration, class can be inherited. So subclass can override getter methods. Here we have to consider two scenarios:
  • 类声明中没有final关键字,类可以被继承。所以子类可以覆盖 getter 方法。这里我们要考虑两种情况:

1. Having Only primitive members:We do not have problem If class has only primitive members, then we do not need to declare class as final.

1.只有原始成员:我们没有问题如果类只有原始成员,那么我们不需要将类声明为final。

2.Having Objects as member variables:If we have objects as member variables then we have to make the members of those objects also final. Means we need to traverse deep down the tree and make all objects/primitives as final which may not be possible all the times. So the workaround is to make the class final which prevents inheritance. So there is no question of subclass overriding getter methods.

2.将对象作为成员变量:如果我们将对象作为成员变量,那么我们必须使这些对象的成员也是最终的。意味着我们需要深入到树的深处,并使所有对象/原语都成为最终的,这可能并非总是可能的。因此,解决方法是使类成为 final 以防止继承。所以不存在子类覆盖 getter 方法的问题。