String object is immutable. What does it mean?

String object is immutable. It can be created in two ways:

  • using an operator new,
  • as a literal using quotes.

A String object does not have setters. Every other method that seemingly changes the value produces another String object instead of modifying the original one. For example:

          
    String s1 = new String("s1");
    String s2 = s1.concat("a");
    String s3 = s1.toUpperCase();

    System.out.println(s1 == s2);       // false
    System.out.println(s1 == s3);       // false
    System.out.println(s2 == s3);       // false
    

As you can see from the example above, the objects s1, s2, or s3 are all different objects. String objects, created using an operator new or as the result of the methods that change the value, have different references even when the resulting values are spelled the same way:

     
    String s1 = new String("s1");
    String s2 = new String("s1");

    System.out.println(s1 == s2);       // false
    System.out.println(s1.equals(s2));  // true

    String s3 = s1.concat("a");
    String s4 = s1.concat("a");
    System.out.println(s3 == s4);       // false
    System.out.println(s3.equals(s4));  // true
     

By the way, as you can see, the method equals() compares String objects by the spelling of their values.

But what about object references? Read Method equals() is the only way to compare String objects for the answer to this question.

Now let us look at the second way of creating a String object. Let us create a String object using a literal (“abc” and “123” are examples of a literal).

Literals are stored in a special area called “string pool”. Every time a new literal is created, JVM checks if such literal already exists in the pool. If yes, then the existing literal is re-used. Which means that two equally spelled literals refer the same String object. Here is the demo code:

        
    String s1 = "s1";
    String s2 = "s1";
    String s3 = "s3";

    System.out.println(s1 == s2);          // true
    System.out.println(s1.equals(s2));     // true

    System.out.println(s1 == s3);          // false
    System.out.println(s1.equals(s3));     // false

    System.out.println(s1 == "s1");        // true
    System.out.println("s1" == "s1");      // true
    System.out.println("s1" == "s3");      // false

    System.out.println(s1.equals("s1"));   // true
    System.out.println("s1".equals("s1")); // true
    System.out.println("s1".equals("s3")); // false
      

In the above examples, references s1 and s2 refer the same object in a string pool because the objects were created from the literals that are spelled the same way “s1”. For the same reason, the reference s1 equals the reference to the literal “s1”.

There are several reasons the literals are stored this way:

  • re-use of long literals optimizes memory usage,
  • strings are used for usernames and password, so keeping them immutable makes the system less susceptible to unauthorized modifications,
  • some resource-intensive calculations on the object (like hash code calculation, for example) has to be done only once if the same literal is reused.

Now you know, what people mean when they say that a String object is immutable: once created, it cannot be changed without creating a new one.

Read more detailed discussion of this topic in the following books:

Send your comments using the link Contact or in response to my newsletter.
If you do not receive the newsletter, subscribe via link Subscribe under Contact.

Powered by WordPress. Designed by Woo Themes