This is a sentence from Java Concurrency in Practice
Shared read-only objects include immutable and effectively immutable objects.
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
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
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.
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. Instead, it returns a new instance with the same value in it. That way, nobody can mutate the state of the Line
class. This makes the Line
class effectively immutable.
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. To do that we're also going to have to imagine that Point
is immutable. Making these assumptions, the getStart()
method could have been able to be written like this:
public Point getStart() {
return start;
}
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.
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.
Instances of a class that is not extensible and whose fields are all final
and themselves immutable are immutable.
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.
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. 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.
Joe-E: A Security-Oriented Subset of Java says
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.