This is the 20th day of my participation in the November Gwen Challenge. Check out the details: The last Gwen Challenge 2021

What is an immutable object? An immutable object is an object whose state cannot be changed after it is created. The state cannot be changed means that the member variables in an object cannot be changed, including the values of the basic data types cannot be changed, the variables of reference types cannot point to other objects, and the state of the objects referred to by reference types cannot be changed.

So just to interrupt the distinction between an object and a reference to an object, the reference to an object is on the stack, and the reference to an object is on the heap, so look at this example String s = “123”; s = “456” ; It appears that s has changed, but it is only the reference s to String that has changed. The object “123” has not changed. Take a look:

We all say that strings are immutable, so let’s look at the source code of String and see how it ensures that strings are immutable.

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 public String(String original) { this.value = original.value; this.hash = original.hash; } public String concat(String str) { int otherLen = str.length(); if (otherLen == 0) { return this; } int len = value.length; char buf[] = Arrays.copyOf(value, len + otherLen); str.getChars(buf, len); return new String(buf, true); } public boolean equals(Object anObject) { if (this == anObject) { return true; } if (anObject instanceof String) { String anotherString = (String) anObject; int n = value.length; if (n == anotherString.value.length) { char v1[] = value; char v2[] = anotherString.value; int i = 0; while (n-- ! = 0) { if (v1[i] ! = v2[i]) return false; i++; } return true; } } return false; }...Copy the code

The String class and the char array that holds the String are both final. This ensures that the String class cannot be inherited, and the value reference itself cannot be changed. However, this does not mean that properties are immutable. Because we can change a value by changing the specific value in the value array.

public static void main(String[] args) {
        char[] value = {'a','b','c','d'};
        System.out.println(value); 
        for (int i = 0; i < value.length; i++) {
            if(i == 1){
                value[i] = 'B';
            }
        }
        System.out.println(value); //aBcd
    }
Copy the code

However, a closer look reveals that value is defined as private, and String does not provide a corresponding GET set method, so we cannot manipulate it. Methods that we often think of as changing String objects, such as subString concat toUpperCase, were used to recreate a char array without changing the original object. This is why we often say that strings are immutable objects. But we can still change the value of a value by reflection, just to show you an example, but we don’t usually do that.

Public static void main(String[] args) throws Exception {// Create a String "Hello World" and assign it to the reference S String s = "Hello World"; System.out.println("s = " + s); / / Hello World / / get the String class in the value Field Field valueFieldOfString = String. Class. GetDeclaredField (" value "); / / change the value attribute access valueFieldOfString setAccessible (true); Char [] value = (char[]) valueFieldofString.get (s); // Change the 5th character in the array referenced by value[5] = '_'; System.out.println("s = " + s); //Hello_World }Copy the code

Why make strings immutable? For efficiency and security, of course, but also because of the high frequency of String usage. The main efficiency is that when I copy a String, I only need to copy the reference, I don’t need to copy the actual object. In a multi-threaded environment, if different threads modify the String at the same time, it doesn’t affect each other. Any change creates a new string, ensuring thread safety.

There’s also a string constant pool in the heap, where all the strings that we’re creating are stored, and when we create the same string, we’re actually pointing to the same place. This saves a lot of space, and of course, String constant pools are possible because strings are immutable objects.

Because String is immutable, the value of hashCode is computed and cached in the field hash when the object is created. This makes String a good primary key in a Map, which is fast. (Because we compute the hash value of the primary key when positioning in the hash table.)

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

In addition, when the database is connected, we pass the user name, password, connected library and other information through the string. If the string is variable, it is likely to be tampered by hackers.

PS. The wrapper classes corresponding to primitive types are immutable objects, again because they are used too often. Suddenly I felt I had learned a lot of details I hadn’t noticed before.

The source version is JDK 1.7