-
- Objective
- Cause
- Deep source
- Is that really immutable?
- Summarize
Objective
These two days in the Java interview related to some of the issues, it is also very lucky to see the following article.
http://blog.csdn.net/zhangjg_blog/article/details/18319521
The author of this article has a series of articles about Java in-depth study, it is worth a look, personally feel very good, very rewarding.
I was touched by a comment that I had read that article. Could not help writing a bit of code to do the next test, to verify.
Cause
As we have understood, by
String"Hello World!";
And
StringnewString("Hello World!");
The resulting string object is not the same, the new method is created in the heap space, and the direct string is first placed in the constant pool. If a new object of the same kind is created, simply let the new object refer to this address in the constant pool.
The advantage is that you can save as few memory space as possible.
The new method is different, as long as you create a string with new, it will open up a piece of memory in the heap space and return a reference to that memory address. So the objects created in this way will not point to the same memory address, even if the content is consistent.
Here's a few simple code to do the next test.
/***字符串中对于内容和地址的判定可以用下面两种方式,但侧重点不一样。*/equals // 判断 两个字符串的内容是否一致== // 判断两个字符串的内存地址是否一致
And look at the following code:
public static void Simple () {String S1 ="Hello world!";String s2 ="Hello world!";String s3 = new String ("Hello world!");String S4 = new String ("Hello world!");Compare references and content below to start comparing System. out. println("String assignment method:");System. out. println(S1==S2);System. out. println(S1. Equals(S2));System. out. println("\ n string assignment method and new mode:");System. out. println(S1==S3);System. out. println(S1. Equals(S3));System. out. println("\nnew Way:");System. out. println(S3==S4);System. out. println(S3. Equals(S4));}
The results are as follows:
字符串赋值方式:truetrue字符串赋值方式和new方式:falsetruenew 方式:falsetrue
It turned out to be the same as what we said.
Deep source
As expected, the string is indeed "immutable", and each change to the bottom is actually a string object that creates a heart and then assigns a new value.
Why is that? We may be able to find the truth in the source code.
Oh, the original Java for the string class just maintained a final type of character array ah. No wonder you can't change after you've assigned a value.
But maybe you have questions, eh, no, "I often change the contents of a string using what the Replace method of string is." What are you explaining? ”
In fact, the answer is still like that, it really did not change, we did not see the truth of the matter, believe that the following source code, you will understand.
/** * Returns A string resulting from replacing all occurrences of* {@codeOldChar}inch ThisString with{@codeNewchar}. * <p> * If the character {@codeOldChar} does notoccurinchThe * character sequence represented by This{@codeString} object, * ThenA reference to This{@codeString} Object isReturned. * Otherwise, a {@codeString} Object isReturned that * represents a character sequence identical to the character sequence * represented by This{@codeString} object, except that every * occurrence of{@codeOldChar} isReplaced byAn occurrence * of{@codeNewchar}. * <p> *Examples: * <blockquote><pre> *"Mesquite in your Cellar". replace (' E ',' O ') * Returns"Mosquito in your Collar"*"The War of Baronets". replace (' R ',' y ') * Returns"The Bayonets"*"sparring with a purple porpoise". replace (' P ',' t ') * Returns"starring with a turtle tortoise"*"Jonl". replace (' Q ',' x ') returns"Jonl"(NoChange) * </pre></blockquote> * *@paramOldChar the old character. *@paramNewchar theNewCharacter. *@returnA string derived from ThisString byReplacing every * occurrence of{@codeOldChar} with{@codeNewchar}. */Public String replace (char OldChar, char Newchar) {if(OldChar! = Newchar) {int len = value.length; int i =-1; Char[] val = value;/ * avoid getfield opcode * / while(++i < Len) {if(Val[i] = = OldChar) { Break; } }if(I < Len) {char buf[] =NewChar[len]; for(Int j =0; J < I; J + +) {Buf[j] = val[j]; } while(I < Len) {char c = val[i]; Buf[i] = (c = = OldChar)? NEWCHAR:C; i++; }return NewString (BUF,true); } }return This; }
The source code is very clear about the use of
newStringtrue);
Returns the new object to the caller.
Is it really immutable?
Read the above content, in fact, basically enough. But to understand something deeper, I believe it would be better for us to program later.
The source code clearly uses char[] value to dress up the external string data. This means that the immutable nature of the string object is actually derived from the final attribute of the value array.
So we can think of that, instead of changing the contents of the string, we turn our head to change the contents of the value array (the value of the private property in the string object can be modified by reflection).
The answer is really going to change oh.
You can look at the following code first
Private Static void Deep() throws Nosuchfieldexception, illegalaccessexception {String Hello ="Hello world!"; String xx =NewString ("Hello world!"); String yy ="Hello world!";/** * Determine if strings are equal, default to memory reference as standard */System. out. println (Hello = = xx); System. out. println (Hello = = yy); System. out. println (xx = = yy);//View Hello, XX, yy the true position of the value array pointed to byField Hello_field = Hello.getclass (). Getdeclaredfield ("Value"); Hello_field.setaccessible (true);Char[] Hello_value = (Char[]) Hello_field.Get(hello); System. out. println (Hello_field.Get(hello)); Field Xx_field = Xx.getclass (). Getdeclaredfield ("Value"); Xx_field.setaccessible (true);Char[] Xx_value = (Char[]) Xx_field.Get(XX); System. out. println (Xx_field.Get(xx)); Field Yy_field = Yy.getclass (). Getdeclaredfield ("Value"); Yy_field.setaccessible (true);Char[] Yy_value = (Char[]) Yy_field.Get(yy); System. out. println (Yy_field.Get(yy));/** * After reflection gets to the lowest reference array of these three string objects value, finds that if the initial content is consistent, the Java bottom point will create the string object to the same character array * * / //Modify string reference value array by reflectionField field = Hello.getclass (). Getdeclaredfield ("Value"); Field.setaccessible (true);Char[]value= (Char[]) field.Get(hello); System. out. println (value);value[5] =' ^ '; System. out. println (value);//Verify if XX has been changedSystem. out. println (XX); }
The result?
falsetruefalse[C@6d06d69c[C@6d06d69c[C@6d06d69cHelloWorld!Hello^World!Hello^World!
It really has changed.
And we can also find that, hello,xx, yy ends up pointing to the same value character array in memory. This also shows that Java is doing a strong enough optimization process at the bottom.
When a string object is created, the underlying will correspond to an array of characters containing the corresponding contents; if another string is present, the reference to the value array can be obtained directly. (As we all know, the array in Java is actually an object type of data, which is not difficult to understand).
The result is the same, whether it is a direct string reference or a new string. The array of characters inside them will point to the same "object" in memory (an array of value characters).
Summarize
A little bit messy, but from this point we can also see that the immutability of string is still in the outside world. At the bottom, Java has made all this transparent. We just need to know that the string object has this feature, that's enough.
For other, everyday applications, it is also possible to use a string object as immutable.
Is Java String really immutable?