A Brief analysis of the Mechanism of Java Immutable Classes

  • 2020-06-03 06:24:05
  • OfStack

Immutable classes (Immutable Class) : An immutable class cannot change the value of its member variables once instance 1 has been created. For example, many immutable classes are built into JDK: Interger, Long and String.

Variable classes (Mutable Class) : A variable class can change the value of its member variables after creating an instance, as opposed to an immutable class. Most classes created in development are mutable classes.

How does the feature of immutable classes benefit JAVA?

1) Thread safety: Immutable objects are thread-safe and can be Shared between threads. No special mechanism is needed to ensure synchronization, because the value of objects cannot be changed. This reduces the possibility of concurrent errors, since there is no need to ensure memory 1 portability by locking mechanisms and so on, and also reduces synchronization overhead.

2) Easy to construct, use and test.

Design principles for immutable classes

How do I write Immutable classes in Java? To write such a class, follow these principles:

1) The state of the immutable object cannot be changed after it is created. Any change to it should result in a new object.

2) All members of the Immutable class should be of private final. In this way member variables are guaranteed to be immutable. But this step is not enough, because if a member variable is an object, it holds only a reference and may externally change the value its reference points to, so point 5 makes up for this

3) The object must be created correctly. For example, object references should not be disclosed during object creation. 4) Only get method is provided to read member variables, and set method is not provided to change member variables, so as to avoid changing the value of member variables through other interfaces and breaking the immutable property.

5) The class should be final to ensure that the class is not inherited. If the class can be inherited, it will break the immutable mechanism of the class. As long as the inherited class overrides the methods of the parent class and the inherited class can change the value of member variables, then once the subclass appears in the form of the parent class, it cannot guarantee whether the current class is changeable.

6) If the class contains an mutable class object, return it to the client with a deep copy of the object instead of the object itself (this can be classed as a special case in Article 1).

If an object passed in by the constructor is directly assigned to a member variable, it is still possible to change the value of an internal variable by modifying the object passed in. Such as:


public final class ImmutableDemo { 
  private final int[] myArray; 
  public ImmutableDemo(int[] array) { 
    this.myArray = array;  // wrong 
  } 
}

Immutability is not guaranteed in this way. myArray and array point to the same block of memory address, and users can change the value inside of myArray outside of ImmutableDemo by modifying the value of the array object. To ensure that the internal values are not modified, use depth copy to create a new memory to hold the incoming values. The right approach:


public final class MyImmutableDemo { 
  private final int[] myArray; 
  public MyImmutableDemo(int[] array) { 
    this.myArray = array.clone();  
  }  
}

Immutable implementation of the String class

String objects are immutable after they are created in memory. Immutable objects are created to meet the above principle. Let's see how the String code is implemented.


public final class String
  implements java.io.Serializable, Comparable<String>, CharSequence
{
  private final char value[]; /** The value is used for character storage. */
  /** The offset is the first index of the storage that is used. */
  private final int offset;
  /** The count is the number of characters in the String. */
  private final int count;
  private int hash; // Default to 0
  ....
  public String(char value[]) {
     this.value = Arrays.copyOf(value, value.length); // deep copy operation 
   }
   public char[] toCharArray() {
    char result[] = new char[value.length];
    System.arraycopy(value, 0, result, 0, value.length);
    return result;
  }
  ...
}

As shown in the code, you can observe that the design of the String class conforms to the design principles summarized above for invariant types. Although the String object sets value to final, it also ensures through various mechanisms that its member variables are immutable. But you can still change its value through reflection. Such as:


String s = "Hello World"; // Create a string "Hello World" .   And assign it to a reference s
System.out.println("s = " + s);   
// To obtain String In the class value field 
Field valueFieldOfString = String.class.getDeclaredField("value");
valueFieldOfString.setAccessible(true); // change value Property 
char[] value = (char[]) valueFieldOfString.get(s);
value[5] = '_'; // change value The first in the referenced array 5 A character 
System.out.println("s = " + s);   //Hello_World The print result is: 
s = Hello World
s = Hello_World

It is found that the value of String has changed. That is, it is possible to modify so-called "immutable" objects through reflection.

Immutable classes are values that cannot be changed after an instance is created. This feature allows immutable classes to provide thread-safe features, but it also introduces the overhead of object creation, where every change to a property recreates a new object. Within JDK, there are also many immutable classes such as Integer, Double and String. The immutable nature of String is primarily intended for constant pooling, thread safety, and class loading. The judicious use of immutable classes can bring great benefits.

Above is the site to introduce Java immutable mechanism analysis, I hope to help you, if you have any questions welcome to leave a message, this site will reply you in time!


Related articles: