Why is the String in Java unchangeable?

Source: Internet
Author: User

Why is the String in Java unchangeable?

What is an immutable object?

As we all know, in Java, the String class is immutable. So what are immutable objects? It can be thought that if an object cannot be changed after it is created, the object is immutable. The state cannot be changed. The member variables in an object, including the values of the basic data type, cannot be changed. The referenced variables cannot point to other objects, the status of the object to which the reference type points cannot be changed.

Differentiate object and object references

For beginners of Java, there is always doubt that String is an immutable object. See the following code:

String s = "ABCabc ";
System. out. println ("s =" + s );

S = "123456 ";
System. out. println ("s =" + s );

The output is as follows:

S = ABCabc
S = 123456

Create a String object s, set the value of s to "ABCabc", and set the value of s to "123456 ". The printed result shows that the value of s has indeed changed. So how can we say that the String object is immutable? In fact, there is a misunderstanding: s is just a String object reference, not the object itself. The object is a memory area in the memory. The more member variables, the larger the space occupied by the memory area. The reference is only a 4-byte data, which stores the address of the object to which it points. The object can be accessed through this address.

That is to say, s is just a reference, it points to a specific object, when s = "123456"; after the code is executed, a new object "123456" is created ", the reference s points to the new object. The original object "ABCabc" still exists in the memory and remains unchanged. Shows the memory structure:

One difference between Java and C ++ is that it is impossible to directly operate on the object itself in Java. All objects are directed by a reference and must be referenced to access the object itself, including obtaining the value of member variables, changing the member variables of an object, and calling methods of an object. In C ++, there are references, objects, and pointers. All three objects can be accessed. In fact, references in Java are similar in concept to pointers in C ++. They all store the address values of objects in the memory, but in Java, references lose some flexibility. For example, references in Java cannot be added or subtracted as pointers in C ++.

Why is the String object unchangeable?

To understand the immutability of String, first let's take a look at the member variables in the String class. In JDK1.6, the String member variables include the following:

 
 
  1. public final class String 
  2.     implements java.io.Serializable, Comparable<String>, CharSequence 
  3.     /** The value is used for character storage. */ 
  4.     private final char value[]; 
  5.  
  6.     /** The offset is the first index of the storage that is used. */ 
  7.     private final int offset; 
  8.  
  9.     /** The count is the number of characters in the String. */ 
  10.     private final int count; 
  11.  
  12.     /** Cache the hash code for the string */ 
  13.     private int hash; // Default to 0 

In JDK1.7, the String class has made some changes, mainly to change the behavior when the substring method is executed, which is irrelevant to the topic of this article. In JDK1.7, the main member variables of the String class are left with two:

 
 
  1. public final class String   
  2.     implements java.io.Serializable, Comparable<String>, CharSequence {   
  3.     /** The value is used for character storage. */   
  4.     private final char value[];   
  5.  
  6.     /** Cache the hash code for the string */   
  7.     private int hash; // Default to 0 

From the code above, we can see that in Java, the String class is actually encapsulation of character arrays. In JDK 6, value is a String-encapsulated array, offset is the starting position of String in the value array, and count is the number of characters occupied by String. In JDK7, there is only one value variable, that is, all characters in value belong to the String object. This change does not affect the discussion in this article. In addition, there is a hash member variable, which is the cache of the hash value of the String object. This member variable is also irrelevant to the discussion in this article. In Java, arrays are also objects. For details, refer to the array features in my previous article java ). So value is just a reference, which points to a real array object. Actually, after executing the String s = "ABCabc"; the actual memory layout should be like this:

Values, offset, and count are all private variables, and public methods such as setValue, setOffset, and setCount are not provided to modify these values. Therefore, strings cannot be modified outside the String class. That is to say, it cannot be modified once initialization, and the three Members cannot be accessed outside the String class. In addition, the values, offset, and count variables are all final. That is to say, once these three values are initialized within the String class, they cannot be changed. Therefore, the String object is considered immutable.

There are some methods in the String, so you can call them to get the changed value. These methods include substring, replace, replaceAll, and toLowerCase. For example, the following code:

 
 
  1. String a = "ABCabc";   
  2. System.out.println("a = " + a);   
  3. a = a.replace('A', 'a');   
  4. System.out.println("a = " + a); 

The output is as follows:

A = ABCabc
A = aBCabc

The value of a seems to have changed, but it is also a misunderstanding. Again, a is just a reference, not a real String object. replace ('A', 'A'), A new String object is created in the method, and the object in the heart is assigned to reference a again. The source code of the replace method in String can be described as follows:

Readers can view other methods by themselves. They re-create a new String object within the method and return this new object. The original object will not be changed. This is why all methods such as replace, substring, and toLowerCase have returned values. This is also why the following call does not change the object value:

 
 
  1. String ss = "123456"; 
  2.  
  3. System.out.println("ss = " + ss); 
  4.  
  5. ss.replace('1', '0'); 
  6.  
  7. System.out.println("ss = " + ss); 

Print result:

Ss = 123456
Ss = 123456

Is the String object immutable?

We can see from the above that the String member variable is private final, that is, it cannot be changed after initialization. Among these Members, value is special because it is a reference variable rather than a real object. Value is modified by final. That is to say, final cannot point to other array objects. Can I change the array to which value points? For example, the character at a certain position in the array is changed to the underscore "_". At least not in the common code we write, because we cannot access this value reference at all, and we cannot modify the array through this reference.

So how can we access private members? Yes, reflection can reflect the value attribute of the String object, and then change the structure of the array through the obtained value reference. The following is the instance code:

 
 
  1. Public static void testReflection () throws Exception {
  2.  
  3. // Create a string "Hello World" and assign it to reference s
  4. String s = "Hello World ";
  5.  
  6. System. out. println ("s =" + s); // Hello World
  7.  
  8. // Obtain the value field in the String class
  9. Field valueFieldOfString = String. class. getDeclaredField ("value ");
  10.  
  11. // Change the access permission of the value Attribute
  12. ValueFieldOfString. setAccessible (true );
  13.  
  14. // Obtain the value of the value Attribute on the s Object
  15. Char [] value = (char []) valueFieldOfString. get (s );
  16.  
  17. // Change the 5th characters in the array referenced by value
  18. Value [5] = '_';
  19.  
  20. System. out. println ("s =" + s); // Hello_World
  21. }

The output is as follows:

S = Hello World
S = Hello_World

In this process, s always references the same String object, but before and after reflection, this String object has changed, that is, through reflection, the so-called "immutable" object can be modified. But we generally do not. This reflection instance can also be said to have a problem: if the status of other objects in the combination of an object can be changed, the object may not be an immutable object. For example, a Car object combines a Wheel object. Although this Wheel object is declared as private final, the internal state of this Wheel object can be changed, the Car object cannot be changed.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.