Is String in JAVA really immutable?

Is String in JAVA really immutable?

Is String immutable? Yes it is! Really want to change? Ok~

We all know that String is an immutable object, that is, once it is created, its state cannot be changed. In this regard, let's analyze a wave.

Internal structure of String

Carefully enter the String inside, we can see that it is a final class, then no one can inherit it, very good, very dink.

Then look directly at its soul, a char array, which is also final, so we know how it is 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

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

   //slightly...
}

Create an object

Use constants to assign values ​​to String variables directly, no matter in several places or several times, they all use the same data.

Unless new a new String.

public class StringTest {

    public static void main(String[] args) {
        String s1 = "abcd";
        String s2 = "abcd";
        String s3 = new String("abcd");
        String s4 = new String("abcd");
        System.out.println("Assign two constants\t s1==s2:" + (s1 == s2));
        System.out.println("Constants and new objects\t s1==s3:" + (s1 == s3));
        System.out.println("Two new objects\t s3==s4:" + (s3 == s4));
    }
}

Output

Assign two constants s1==s2:true
Constants and new objects s1==s3:false
Two new objects s3==s4:false

Use reflection to modify values

Add something after the above code, try to modify the value of s1.

public class StringTest {

    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
        String s1 = "abcd";
        String s2 = "abcd";
        String s3 = new String("abcd");
        String s4 = new String("abcd");
        System.out.println("Assign two constants\t s1==s2:" + (s1 == s2));
        System.out.println("Constants and new objects\t s1==s3:" + (s1 == s3));
        System.out.println("Two new objects\t s3==s4:" + (s3 == s4));

       //Get the value field hidden by String through reflection
        Field f = String.class.getDeclaredField("value");

       //Let it open up
        f.setAccessible(true);

       //Get the internal value array of s1
        char[] v = (char[]) f.get(s1);

       //change its first letter
        v[0] ='x';

        System.out.println("After the change...");
        System.out.println("s1 = "+ s1);
        System.out.println("s2 = "+ s2);
        System.out.println("s3 = "+ s3);
        System.out.println("s4 = "+ s4);
        System.out.println("Assign two constants\t s1==s2:" + (s1 == s2));
        System.out.println("Constants and new objects\t s1==s3:" + (s1 == s3));
        System.out.println("Two new objects\t s3==s4:" + (s3 == s4));
    }
}

Output

Assign two constants s1==s2:true
Constants and new objects s1==s3:false
Two new objects s3==s4:false
After the change...
s1 = xbcd
s2 = xbcd
s3 = xbcd
s4 = xbcd
Assign two constants s1==s2:true
Constants and new objects s1==s3:false
Two new objects s3==s4:false

summary

1. The value inside the String can really be changed through reflection. 2. Directly changing the value will cause other String objects with the same value to be changed (so can guess the same data actually used at the bottom layer?) 3. Although the values ​​are all changed, But as an object, the relationship between the 4 variables has not changed (the two Strings of new and the other two are still not equal) 4. It is dangerous to do this 5. It is boring to do so