Chapter:Classes - Strings are immutable
Meta information about this chapter
Expand using link to the right to see the full content.
We wanted to include the concept of immutability in this course material, but not dive too deep into the matter. Therefore, we are using String as an example of immutable classes.
Knowing about immutability is key to import both classes in the Java API (the wrapper classes Integer, Double etc, and BigDecimal and its friends, and of course String), and code that the students are bound to encounter in the wild.
In fact, mutability is key to understand how the String class works and behaves, and String is surely the most common type in many applications. Understanding how String is immutable also helps understand the need and applications for the StringBuilder class.
So, the purpose of this chapter is to prepare the students for immutability and thus grasp how String objects behave differently from mutable objects from classes the student typically writes herself.
After this chapter, the student shall understand:
- Mutability on a basic level
- That Strings are immutable - and what the result of calling e.g.
- How mutability is achieved (on a basic level)
- No manipulation of private variable to change state
- Returning a new instance with a new state in mutator methods
- That mutability exists in many classes in the API
- That some people strongly advise to use mutability as much as possible
- That other people are not so strongly opinionated
Instructions to the teacher
Some students will panic when they understand the nature of String objects, in that they can't be changed "inplace", since all methods with names indicating a change of state rather returns a reference to a new String with the new state. Respect this and motivate this potentially new insight by telling them that lots of classes in the API are immutable and that this must be understood in order to become a Java programmer.
If they ask if mutable classes (like many classes they have seen and written so far) are "wrong", explain that this is a matter of taste and style.
There are subtle benefits from using immutability like thread-safety (which is a concept outside of the scope of this course material), pooling (like the constant pools of String, Integer, Double etc). Since an object of class Integer can't be changed, we can reuse the same object without worrying about it being changed. Note that the number of values pooled in the wrapper classes is limited!
One can also argue that the benefit of mutability, on the other hand, is that objects whose state frequently changes, would result in a lot of object creation if everything was immutable. As an example, use the difference between updating a String in a loop and updating a StringBuilder. At least in theory, the StringBuilder seems like the more memory efficient alternative, since updating an immutable String in a loop, would result in new objects in every iteration.
Classes: Strings are immutable
Some objects are impossible to change once they are created. Such objects are said to be "immutable". Strings are examples of such objects. Once you have created a String, you cannot change it.
There are instance methods in the class String which might lead you to think that you can change a String object, such as toLowerCase(), concat(), append() etc.
But every such instance method in the class String actually returns a reference to a brand new String object with a state as if the previous object would have been changed!
Some examples might be in place:
// Change all letters to lower case: String city = "Liverpool"; String lowerCaseCity = city.toLowerCase();
In the above example code, we must save the result of calling toLowerCase() in a variable if we are to use it. Simply calling
city.toLowerCase() doesn't change the textual contents of the String referred to by
city. So, this code below would compile but not change anything:
// call toLowerCase() String city = "Liverpool"; city.toLowerCase(); // city is still representing "Liverpool" with a capital "L"
The append() method works in a similar way:
String city = "Liverpool"; String cityAndCountry = city.concat(", Great Britain");
Simply calling concat() on a String reference doesn't change the String referred to by the reference. It actually creates a new String object with the contents produced from concatenating the original String with the argument, and returns a reference to this new String. All instance methods in String works this way.
By the way, how do we check if two reference variables refer to the same instance/object? We can use the
When applied to reference variables, the
== operator compares the "address" (reference) of the two variables, which means "do they refer to the exact same object in memory?".
Consider the following snippets:
Member first = new Member("James"); Member second = first; Member third = new Member("James"); System.out.println(first == second); // true - same object! System.out.println(first == third); // false - same name but different objects! System.out.println(second == second);// true - same object! System.out.println(second == third); // false - same name but different objects!
And, using Strings:
String name = "James"; String fullName = name.concat(" Brown"); System.out.println(name == fullName); // false - concat creates a new object! System.out.println( name == name.concat(" Stewart") ); // false - concat creates a brand new object!
If we want to check whether two different objects should be considered "equal" to each other, we must use a method called equals() instead. String has a functioning version of this method:
String name = new String("James"); String otherName = new String("James"); System.out.println( name.equals(otherName) ); // true - different objects, but the same contents!
Bonus information (you may skip this part if you want, it is only for the keen students who want to know the whole truth):
There is actually something special with some immutable classes like String. Java maintains a pool of String objects created with the special syntax with double quotes:
String s = "Some text";. Since Strings are immutable and will never change, they can be reused by the runtime system. So creating two Strings using the double quote style with the same text, actually only creates one String object! So this would print true:
String one = "Hello"; String two = "Hello"; System.out.println(one == two); // true - actually only one object is created and reused...
But using the operator
new when creating a String really creates a brand new object, regardless of the pool of reusable existing String objects. So the following will print "false":
String one = "Hello"; String two = new String("Hello"); System.out.println(one == two); // false - the operator new forces the creation of a new object!
Chapters about classes
Here are the chapters about classes in this book, so that you can keep a check on your progress:
- Chapter:Classes_-_Strings_are_immutable « you are here!
Hey! After the exercise chapter (next), you are done with all the chapters on Classes! Well done!
- Oracle tutorial - Strings
- Oracle tutorial - Immutable Objects
- Oracle tutorial - A Strategy for Defining Immutable Objects
- DZone-JavaZone - Why String is Immutable in Java
- Java 8 online API documentation for java.lang.String
Where to go next
Next page has exercises for this chapter: Classes_-_Strings_are_immutable_-_Exercises