Immutable class?

2019-01-02 20:20发布

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

8条回答
泪湿衣
2楼-- · 2019-01-02 20:24

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.

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 ImmutableInt can only be set when the object is instantiated, and by having only a getter (getValue) the object's state cannot be changed after instantiation.

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 ArrayList to be obtained through an getter will allow the internal state to change by changing the array or collection:

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 ArrayList can be obtained through getList and be manipulated, leading to the state of the object itself to be altered, therefore, not immutable.

// 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:

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.

查看更多
裙下三千臣
3楼-- · 2019-01-02 20:25

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

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.

查看更多
无与为乐者.
4楼-- · 2019-01-02 20:27

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.

查看更多
琉璃瓶的回忆
5楼-- · 2019-01-02 20:29

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.

查看更多
琉璃瓶的回忆
6楼-- · 2019-01-02 20:33

Another way to make immutable object is using Immutables.org library:

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):

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)
  }
}
查看更多
余欢
7楼-- · 2019-01-02 20:35

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.

to be immutable should satisfy following,

  • Al the variables should be private.
  • No mutator methods(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.

/**
* 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

查看更多
登录 后发表回答