What are immutable objects?
A string object is immutable, but this only means that you cannot change its value by calling its public method.
As we all know, in Java, the string class is immutable. So what exactly is immutable object? Consider this: If an object cannot change its state after it has been created, the object is immutable. The inability to change the state means that you cannot change the member variables within an object, including the value of the base data type, and the variable of the reference type cannot point to another object, and the state of the object to which the reference type points cannot change.
Differentiating objects and objects from references
For Java beginners, there is always doubt about string being immutable objects. Look at the following code:
String s = "ABCABC";
System.out.println ("s =" + s);
s = "123456";
System.out.println ("s =" + s);
Printing results are:
First create a String object s, then let s the value of "Abcabc", and then let s the value of "123456". As you can see from the print result, the value of S is really changing. So how do you say that a string object is immutable? There is a myth here: s is just a reference to a string object, not the object itself. The object is in memory a piece of memory, and the more member variables, the larger the space the memory area occupies. A reference is just a 4-byte data containing the address of the object to which it is directed, and the object can be accessed through this address.
That is, S is just a reference, it points to a specific object when s= "123456"; After this code was executed, a new object "123456" was created, and the reference s to the object of the heart, the original object "Abcabc" still exists in memory, and does not change. The memory structure is shown in the following illustration:
One difference between Java and C + + is that in Java it is impossible to manipulate the object itself directly, all objects are pointed by a reference and must be referenced to access the object itself, including getting the value of the member variable, changing the object's member variable, invoking the object's method, and so on. In C + + There are references, objects, and pointers three things, all three of which can access objects. In fact, references in Java and pointers in C + + are conceptually similar, they are the address values of the objects in memory, but in Java, the reference loses some flexibility, such as a reference in Java that does not add and subtract as a pointer in C + +.
Why is a string object immutable?
To understand the immutability of a string, first look at what member variables are in the string class. In JDK1.6, there are several member variables for string:
Public final class String
implements Java.io.Serializable, Comparable<string>, charsequence
{
/** The value is used for character storage. *
Private final char value[];
/** the ' offset is ' the ' storage ' is used. * *
private final int offset;
/** The count is the number of characters in the String. *
private final int count;
/** Cache The hash code for the string */
private int hash;//Default to 0
In JDK1.7, the string class makes some changes, primarily by changing the behavior of the substring method when it is executed, which is irrelevant to the subject of this article. The main member variables of the string class in JDK1.7 have two left:
Public final class String
implements Java.io.Serializable, Comparable<string>, charsequence {
/** the The value is used for character storage. *
Private final char value[];
/** Cache The hash code for the string */
private int hash;//Default to 0
As you can see from the above code, the string class in Java is actually an encapsulation of a character array. In JDK6, value is a string encapsulated array, offset is the starting position of string in this value array, and count is the number of characters that string occupies. 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, and this member variable is irrelevant to the discussion in this article. In Java, arrays are also objects (you can refer to the attributes of an array in my previous article Java). So value is just a reference, and it points to a real array object. Actually executes the string s = "ABCABC"; After this code, the real memory layout should be this:
The three variables, Value,offset and count, are private and do not provide public methods such as SetValue, SetOffset, and setcount to modify the values, so the string cannot be modified outside of the string class. That is, once initialized, it cannot be modified, and the three members cannot be accessed outside the string class. In addition, the three variables, Value,offset and count, are final, meaning that within the string class, once the three values have been initialized, they cannot be changed. So you can think of a string object as immutable.
So in string, there are some methods that call them to get the changed value. These methods include substring, replace, replaceall, tolowercase, etc. For example, the following code:
String a = "abcabc";
System.out.println ("a =" + a);
A = A.replace (' A ', ' a ');
System.out.println ("a =" + a);
Printing results are:
Then the value of a seems to change, in fact, is the same mistake. Again, A is just a reference, not a real string object, and when calling A.replace (' a ', ' a '), a new string object is created inside the method, and the object of the heart is returned to reference a. The source code for the Replace method in string can indicate the problem:
Readers can view other methods themselves by recreating the new string object within the method, and returning the new object, the original object will not be changed. This is also why the methods such as replace, Substring,tolowercase, and so on, have return values. And why calls like this do not change the value of an object:
String ss = "123456";
SYSTEM.OUT.PRINTLN ("ss =" + ss);
Ss.replace (' 1 ', ' 0 ');
SYSTEM.OUT.PRINTLN ("ss =" + ss);
Print results:
is a string object really immutable?
As you can know from the above, the member variable of a string is private final, which is not changed after initialization. So in these members, value is special because he is a reference variable, not a real object. Value is final decorated, which means that final cannot point to other array objects, so can I change the array that value points to? For example, the characters in a position in an array are changed to underscore "_". At least we can't do it in the normal code we write ourselves, because we can't access the value reference at all, and we can't modify the array through that reference.
So what is the way to access private members? Yes, with reflection, you can reflect the value attribute in a String object and change the structure of the array by the value reference obtained. Here is the instance code:
The public static void Testreflection () throws Exception {
//creates the string "Hello World" and assigns to the reference s
string s = "Hello World";
System.out.println ("s =" + s); Hello World
//Get the Value field in the String class
field valuefieldofstring = String.class.getDeclaredField ("value")
; Change the access rights of the Value property
valuefieldofstring.setaccessible (true);
Gets the value of the values property on the S object
char[] value = (char[]) valuefieldofstring.get (s);
Change the 5th character in the array referenced by value
value[5] = ' _ ';
System.out.println ("s =" + s); Hello_world
}
Printing results are:
s = Hello World
s = Hello_world
In this procedure, s always refers to the same string object, but before and after reflection, the string object changes, that is, by reflection, it is possible to modify the so-called "immutable" object. But we don't usually do that. This reflection can also illustrate a problem: If an object, the state of the other objects of his composition can be changed, then the object is probably not an immutable object. For example, a car object that combines a wheel object, although this wheel object is declared private final, but the state within the wheel object can be changed, then it is not good to ensure that the car object is immutable.