Java mutable and immutable types

meaning

immutable : variables that are assigned once and never reassigned.
mutable : When you assign to a variable or a field, you're changing where the variable's arrow points. You can point it to a different value. When you assign to the contents of a mutable value – such as an array or list – you're changing references inside that value.

give an example

For example, String and StringBuilder:

  • String is immutable. Every time you modify a string object, a new string object will be generated, while the original object remains unchanged.
  • StringBuilder is mutable because every modification to its object acts on the object itself and does not produce a new object.

Java immutable class

1. Introduction to immutable class

Immutable class: the so-called immutable class means that once the instance of this class is created, its member variable value cannot be changed. In the Java class library, all wrapper classes of basic types are immutable classes (Byte, Boolean, Short, Char, Integer, Float, Long, Double), and String is also immutable.
Variable class: compared with immutable class, variable class can change its member variable value after creating an instance. Most classes created in development belong to variable class.

2. Advantages of immutable class

Having finished the difference between variable classes and immutable classes, we need to further understand why there are immutable classes? What benefits does this feature bring to JAVA?

  • Thread safety
  • Immutable objects are thread safe and can be shared among threads. There is no need to use special mechanisms to ensure synchronization, because the value of the object cannot be changed. It can reduce the possibility of concurrent errors, because there is no need to use some locking mechanisms to ensure memory consistency, and reduce the synchronization overhead.
  • Easy to construct, use and test
  • ...

3. Disadvantages of immutable classes

  • Using immutable types, frequent modifications to them will produce a large number of temporary copies (garbage collection is required);
  • For the possible risks caused by variable types, we return a new variable type object to the client through defensive copy (deep copy). Most of the time, the copy will not be modified by the client,
    It may cause a lot of memory waste.

4. Design method of immutable class

For the design immutable class, I summarize the following principles:

a. Add the final modifier to the class to ensure that the class is not inherited.

If the class can be inherited, it will destroy the immutability 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 the member variable, once the child class appears in the form of the parent class, it cannot guarantee whether the current class is changeable.

b. Ensure that all member variables must be private and decorated with final

In this way, ensure that the member variables cannot be changed. However, this step is not enough, because if it is an object member variable, its value may be changed externally. So point 4 makes up for this deficiency.

c. It does not provide methods to change member variables, including setter s

Avoid changing the value of member variables through other interfaces and damaging immutability.

d. Initialize all members through the constructor for deep copy

If a class member is not an original variable (such as int, double) or an immutable class, the immutability of the class must be ensured by using the deep copy method when initializing the member or using the get method. For example:

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

This method cannot guarantee immutability. MyArray and array point to the same memory address. Users can change the internal value of myArray by modifying the value of array object outside ImmutableDemo. In order to ensure that the internal value is not modified, you can use deep copy to create a new memory to store the incoming value. Correct practice:

public final class MyImmutableDemo {  
    private final int[] myArray;  
    public MyImmutableDemo(int[] array) {  
        this.myArray = array.clone();   
    }   
}
e. In the getter method, instead of directly returning the object itself, clone the object and return a copy of the object

This method is also to prevent object leakage and direct operation on member variables after obtaining internal variable member objects through getter s, resulting in changes to member variables.

Immutability of String object

String objects cannot be changed after they are created in memory. The creation of immutable objects generally meets the above five principles. Let's see how the string code is implemented.

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence
{
    /** The value is used for character storage. */
    private final char value[];
    /** 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;
    /** Cache the hash code for the string */
    private int hash; // Default to 0
    ....
    public String(char value[]) {
         this.value = Arrays.copyOf(value, value.length); // deep copy operation
     }
    ...
     public char[] toCharArray() {
     // Cannot use Arrays.copyOf because of class initialization order issues
        char result[] = new char[value.length];
        System.arraycopy(value, 0, result, 0, value.length);
        return result;
    }
    ...
}

As shown in the above code, the following design details can be observed:

  • The String class is decorated with final and cannot be inherited
  • All members inside string are set as private variables
  • There is no setter for value
  • And set value and offset to final.
  • When the variable array value [] is passed in, copy instead of directly copying value [] to internal variables
  • When getting value, it does not directly return the object reference, but the copy of the object

This is consistent with the invariant type characteristics summarized above, and also ensures that the String type is an immutable class.

Advantages and disadvantages of immutability of String objects

advantage

a. Need for string constant pool

You can save space by placing constants in the same character pool every time you create them. However, if the String is variable, the String with the same content also points to the same memory space of the constant pool. When a variable changes the value of the memory, other traversal values will also change. Therefore, it does not meet the original intention of constant pool design.

b. Thread safety considerations.

The same string instance can be shared by multiple threads. This eliminates the need to use synchronization for thread safety issues. The string itself is thread safe.

c. The class loader uses strings

Immutability provides security so that the correct class is loaded. For example, you want to load Java sql. Connection class, and this value is changed to myhacked Connection, it will cause unknowable damage to your database.

d. Support hash mapping and caching.

Because the string is immutable, the hashcode is cached when it is created and does not need to be recalculated. This makes the string very suitable as the key in the Map, and the processing speed of the string is faster than other key objects. This is why keys in HashMap often use strings.

shortcoming

If there is a need to change the value of a String object, a large number of String objects will be created.

Is the String object really immutable

String class source code:

public final class String implements java.io.Serializable,Comparable<String>, CharSequence {
    /** The value is used for character storage. */
    private final char value[];

    /** Cache the hash code for the string */
    private int hash; // Default to 0

    /** use serialVersionUID from JDK 1.0.2 for interoperability */
    private static final long serialVersionUID = -6849794470754667710L;
    ...

Although the String object sets value to final, and various mechanisms are used to ensure that its member variables cannot be changed. However, its value can still be changed by means of reflection mechanism. For example:

//Create the string "Hello World" and assign it to the reference s
	String s = "Hello World"; 
	System.out.println("s = " + s);	//Hello World

	//Gets the value field in the String class
	Field valueFieldOfString = String.class.getDeclaredField("value");
	//Change the access permission of the value attribute
	valueFieldOfString.setAccessible(true);

	//Gets the value of the value attribute on the s object
	char[] value = (char[]) valueFieldOfString.get(s);
	//Change the 5th character in the array referenced by value
	value[5] = '_';
	System.out.println("s = " + s);  //Hello_World

The print result is:

s = Hello World
s = Hello_World

summary

Immutable class means that the value of member traversal cannot be changed after the instance is created. This feature makes immutable classes provide thread safe features, but it also brings the overhead of object creation. Every time a property is changed, a new object is created. JDK also provides many immutable classes, such as Integer, Double, String, etc. The immutability of String is mainly to meet the requirements of constant pool, thread safety and class loading. Rational use of immutable classes can bring great benefits.

Keywords: Java

Added by spider661 on Mon, 07 Feb 2022 13:18:46 +0200