简体   繁体   English

不可变和有效不可变对象之间的区别?

[英]Different between immutable and effectively immutable objects?

This is a sentence from Java Concurrency in Practice 这是Java Concurrency in Practice中的一句话

Shared read-only objects include immutable and effectively immutable objects. 共享只读对象包括不可变和有效不可变对象。

What are the differences between immutable and effectively immutable objects? 不可变和有效不可变对象之间有什么区别?

Instances of a class that is not extensible and whose fields are all final and themselves immutable are immutable. 不可扩展且其字段都是final且本身不可变的类的实例是不可变的。

Instances of a class whose fields cannot be mutated because of details of its methods are effectively immutable. 由于其方法的细节而无法变异的类的实例实际上是不可变的。 For example: 例如:

final class C {
  final boolean canChange;
  private int x;
  C(boolean canChange) { this.canChange = canChange; }
  public void setX(int newX) {
    if (canChange) {
      this.x = newX;
    } else {
      throw new IllegalStateException();
    }
  }
}

Some instances of C are effectively immutable and some are not. C某些实例实际上是不可变的,有些则不是。

Another example is zero-length arrays. 另一个例子是零长度数组。 They are effectively immutable even though their containing class is not provably immutable since there is no element of them which can be changed. 它们实际上是不可变的,即使它们的包含类不可证明是不可变的,因为它们中没有可以改变的元素。


Joe-E uses a verifier to prove that some classes only allow for immutable instances. Joe-E使用验证程序来证明某些类仅允许不可变实例。 Anything marked with the Immutable marker interface are checked and certain classes like String (effectively immutable since its char[] does not escape) are grandfathered in as immutable. 任何标有Immutable标记接口的东西都会被检查,并且像String这样的String (因为它的char[]不会逃脱而实际上是不可变的)会被视为不可变的。

Joe-E: A Security-Oriented Subset of Java says Joe-E:一个面向安全的Java子集

The Immutable interface, defined by the Joe-E library, is treated specially by the language: the Joe-E verifier checks that every object implementing this interface will be (deeply) immutable, and raises a compile-time error if this cannot be automatically verified. 由Joe-E库定义的Immutable接口由语言专门处理:Joe-E veri fi er检查实现此接口的每个对象是否(深度)不可变,如果不能自动生成,则会引发编译时错误VERI网络版。

Here's my understanding from a bit of googling and finding this article . 这是我从谷歌搜索和发现这篇文章的理解。 An Effectively Immutable Object is an object that contains fields that can be mutated, but it doesn't let anything mutate those fields because it never gives you a reference to them. 一个有效不可变的对象是一个包含可以变异的字段的对象,但它不会让任何东西改变这些字段,因为它永远不会给你一个引用。 For example, lets say you create a class with an ArrayList in it. 例如,假设您创建了一个包含ArrayList的类。 ArrayList s are mutable, but if your class always returns a copy of the ArrayList and everything else in your class is immutable, then your class has become effectively immutable: There's no way to mutate the state of an instance of your class. ArrayList是可变的,但是如果你的类总是返回ArrayList的副本,并且你的类中的其他所有东西都是不可变的,那么你的类已经变得有效不可变:没有办法改变你的类的实例的状态。

The blog post gives this as an example of an effectively immutable class: 博客文章将此作为有效不可变类的示例:

import java.awt.*;

public class Line {

   private final Point start;
   private final Point end;

   public Line(final Point start, final Point end) {
       this.start = new Point(start);
       this.end = new Point(end);
   }

   public void draw() {
       //...
   }

   public Point getStart() {
       return new Point(start);
   }

   public Point getEnd() {
       return new Point(end);
   }
}

Point objects are mutable, but that's ok, because this class does not give anyone the direct reference to it's Point instances. Point对象是可变的,但没关系,因为这个类没有给任何人直接引用它的 Point实例。 Instead, it returns a new instance with the same value in it. 相反,它返回一个具有相同值的新实例。 That way, nobody can mutate the state of the Line class. 这样,没有人可以改变Line类的状态。 This makes the Line class effectively immutable. 这使得Line类有效地不可变。

So how is this different from a truly immutable class? 那么这与一个真正不可改变的阶级有什么不同呢? A truly immutable class has fields that are also immutable. 一个真正不可变的类具有也是不可变的字段。 Lets imagine Line was truly immutable. 让我们想象Line是真正不可改变的。 To do that we're also going to have to imagine that Point is immutable. 要做到这一点,我们还必须想象Point是不可变的。 Making these assumptions, the getStart() method could have been able to be written like this: 做出这些假设, getStart()方法可以像这样编写:

public Point getStart() {
   return start;
}

Take a look at this answer: 看看这个答案:

effectively immutable and immutable The difference between effectively immutable and immutable is that in the first case you still need to publish the objects in a safe way. 有效不可变和不可变有效不可变和不可变之间的区别在于,在第一种情况下,您仍然需要以安全的方式发布对象。 For the truly immutable objects that isn't needed. 对于不需要的真正不可变对象。 So truly immutable objects are preferred because they are easier to publish, the reasons I stated above say why you might prefer unsynchronized publication. 所以真正的不可变对象是首选,因为它们更容易发布,我上面说的原因说明为什么你可能更喜欢不同步的发布。

https://stackoverflow.com/a/7887675/1007546 https://stackoverflow.com/a/7887675/1007546

Immutable objects completely encapsulates their internal state and they do not allow modification of that state after construction (possibly with the use of final, etc) therefore they are safe to share between multiple threads because reading from a shared object is not harmful from multiple threads. 不可变对象完全封装了它们的内部状态,并且它们不允许在构造之后修改该状态(可能使用final等),因此它们在多个线程之间共享是安全的,因为从共享对象读取对多个线程无害。

Effectively immutable objects may change their state prior to being shared between multiple threads, but after they are "published" (ie multiple references are given to several threads) they protect themselves from modification. 有效的不可变对象可以在多个线程之间共享之前改变它们的状态,但是在它们被“发布”之后(即多个引用被赋予多个线程)它们保护自己不被修改。

Immutable objects prevent you from using useful software engineering practices like lazy initialization because in order to lazy init a property or field they have to be mutable violating the carefree concurrency sharing property of them. 不可变对象阻止您使用有用的软件工程实践,如延迟初始化,因为为了延迟属性或字段,它们必须是可变的,违反了它们的无忧无虑的并发共享属性。 Effectively immutable objects relax these constraints to get a best of both worlds approach by carefully knowing when they can safely modify their internal state and when it is forbidden. 有效的不可变对象通过仔细地知道何时可以安全地修改其内部状态以及何时被禁止来放松这些约束以获得两种世界方法的最佳效果。

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

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