Explore strings, StringBuilder, and StringBuffer in Java

Source: Internet
Author: User
Tags java se

Explore strings, StringBuilder, and StringBuffer in Java

I believe that the string class is one of the most frequently used classes in Java, and it is a place that the major companies interview like to ask, and today come and learn about the string, StringBuilder, and StringBuffer classes, Analyze their similarities and differences and understand the scenarios that each class applies to. The following is the directory outline for this article:

A. Do you understand the string class?

Two. In-depth understanding of string, StringBuffer, StringBuilder

Three. Performance testing of three classes under different scenarios

Four. Common questions about string and stringbuffer (rumor about some of the distorted string classes circulated on the Internet)

If there is a point, please forgive and correct, I appreciate it.

Please respect the author's labor results, reprint please indicate the address:

Http://www.cnblogs.com/dolphin0520/p/3778589.html

A. Do you understand the string class?

To understand a class, the best way is to look at the implementation of this class of source code, the implementation of the String class

The \jdk1.6.0_14\src\java\lang\string.java file.

Opening the class file will reveal that the string class is final decorated:

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 first index of the storage, which 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    /** with serialversionuid from JDK 1.0. 2 for Interoperability */    private static final long serialversionuid = -6849794470754667710l;    ......}

From the above you can see the points:

1) The String class is the final class, meaning that the string class cannot be inherited, and its member methods default to the final method. In Java, a class that is final decorated is not allowed to be inherited, and the member methods in the class default to the final method. In earlier versions of the JVM implementation, the final modified method was converted into inline invocation to improve execution efficiency. And starting with Java SE5/6, it's getting rid of this way. Therefore, in the current version of the Java SE, it is not necessary to consider using final to increase the efficiency of the method invocation. The method is set to final only if you are sure that you do not want the method to be overwritten.

2) The above lists all the member properties in the String class, from which you can see that the string class actually holds strings through a char array.

Let's look at some of the method implementations of the String class:

Public String substring (int beginindex, int endIndex) {if (Beginindex < 0) {throw new Stringindexoutofboundsexcepti On (beginindex);} if (EndIndex > Count) {throw new stringindexoutofboundsexception (EndIndex);} if (Beginindex > EndIndex) {throw new stringindexoutofboundsexception (Endindex-beginindex);} Return ((Beginindex = = 0) && (endIndex = = count))?    This:new String (offset + beginindex, endindex-beginindex, value); public string concat (string str) {int otherlen = Str.length (), if (Otherlen = = 0) {return this;} Char buf[] = new Char[count + otherlen];getchars (0, Count, buf, 0); Str.getchars (0, Otherlen, buf, Count); return new String    (0, Count + otherlen, buf);    } public String replace (char OldChar, char Newchar) {if (OldChar! = Newchar) {int len = count;    int i =-1; Char[] val = value;   /* Avoid GetField opcode */int off = offset;    /* Avoid GetField opcode */while (++i < Len) {if (Val[off + i] = = OldChar) {break;} }   if (i < len) {char buf[] = new Char[len];for (int j = 0; J < i; J + +) {Buf[j] = val[off+j];}    while (I < Len) {char c = val[off + i]; Buf[i] = (c = = OldChar)?    NEWCHAR:C; i++;}    return new String (0, Len, buf); }}return this;

As can be seen from the three above methods, whether the sub, concat, or replace operations are not performed on the original string, a new string object is regenerated. This means that the most primitive string has not been changed after these operations.

Here is a point to remember forever:

 "Any changes to the string object do not affect the original object, and any related change operations will generate a new object."

After learning about the basics of the string class, here are some areas that you can easily ignore and confuse in your usual use.

Two. In-depth understanding of string, StringBuffer, StringBuilder

1.String str= The difference between "Hello World" and string Str=new string ("Hello World")

Presumably everyone on the above 2 statements are not unfamiliar, in peacetime writing code in the process also often encountered, then they exactly what difference and contact? Let's look at a few examples below:

public class Main {public static void main (string[] args) {String str1 = ' Hello World '; String str2 = new string ("Hello World"); String str3 = "Hello World"; String STR4 = new string ("Hello World"); System.out.println (STR1==STR2); System.out.println (STR1==STR3); System.out.println (STR2==STR4);}}

The output of this code is

  

Why do you have such a result? Let's explain why:

In a previous blog post on the memory mechanism of the JVM, it was mentioned in a section of the class file that the literal constants and symbolic references generated during compilation are stored, which is called the class file constant pool, which corresponds to the run-time pool of the method area during the run.

So in the above code, string str1 = "Hello World"; and string str3 = "Hello World"; Both literal constants and symbolic references are generated during compilation, and the literal constant "Hello World" is stored in the run-time pool (of course only one copy) during the run. By binding a string object to a reference in this way, the JVM execution engine looks for the same literal constant in the run-time pool, and if it does, points the reference directly to the literal constant that already exists, or creates a space in the run-time pool to store the literal constant. and point the reference to the literal constant.

As is known to all, the generation of objects through the New keyword is done in the heap area, and the process of object generation in the heap is not to detect whether the object already exists. As a result, objects are created by using new, which must be different objects, even if the contents of the strings are the same.

The difference between 2.String, StringBuffer and StringBuilder

Since the string class already exists in Java, why do you need StringBuilder and StringBuffer classes?

So look at the following code:

public class Main {public static void main (string[] args) {string string = ' "; for (int i=0;i<10000;i++) {string + =" Hello ";}}}

This string + = "Hello", the procedure is equivalent to the original string variable point to the object contents of the "Hello" as a string addition to the next one to save into another new string object, and then the string variable point to the newly generated object. If you have any questions you can decompile their bytecode file is clear:

  

It is clear from this decompile bytecode file that starting from line 8th to line 35th is the execution of the entire loop, and each time the loop is new to a StringBuilder object, then the append operation is performed, and finally the string object is returned by the ToString method. In other words, this loop is finished. New has 10,000 objects, imagine, if these objects are not recycled, it will cause a lot of memory resources wasted. It can also be seen from the above that the operation of string+= "Hello" is in fact automatically optimized by the JVM:

StringBuilder str = new StringBuilder (string);

Str.append ("Hello");

Str.tostring ();

Let's look at the following code:

public class Main {public static void main (string[] args) {StringBuilder StringBuilder = new StringBuilder (); for (int i=0;i <10000;i++) {stringbuilder.append ("Hello");}}}

The anti-compile bytecode file gets:

  

It can be seen from here that the for loop of this code ends at 13 lines to 27 lines, and the new operation is done only once, i.e. only one object is generated, and the append operation is based on the original object. So after 10,000 cycles, this code takes up much less resources than the above.

Then some people will ask, since the StringBuilder class, why do you need StringBuffer class? See the source code at a glance, in fact, the StringBuilder and StringBuffer classes have the same member properties and member methods are basically the same, the difference is the StringBuffer class of member methods before a keyword: synchronized, do not say more, This keyword is secured during multithreaded access, meaning that StringBuffer is thread-safe.

The following is a 2 snippet of code from the StringBuffer and Stringbuilder,insert methods of the specific implementation:

Insert method for StringBuilder

  Public StringBuilder Insert (int index, char str[], int offset,                                int len)     {        Super.insert (index, str, offset, le n); return this;    }

Insert method for StringBuffer:

Public synchronized StringBuffer Insert (int index, char str[], int offset,                                            int len)     {        Super.insert (index, STR, offset, len);        return this;    }
Three. Performance testing of three classes under different scenarios

We've seen the difference between the three classes from the second section, and we're going to do a little test to test the performance differences of the three classes:

public class Main {private static int time = 50000;public static void Main (string[] args) {teststring (); Teststringbuffer () ; Teststringbuilder (); test1string (); test2string ();} public static void TestString () {String s= "", Long begin = System.currenttimemillis (); for (int i=0; i<time; i++) {s + = "Java"; } Long over = System.currenttimemillis (); SYSTEM.OUT.PRINTLN ("Operation" +s.getclass (). GetName () + "type is used for:" + (Over-begin) + "MS"); }public static void Teststringbuffer () {stringbuffer sb = new StringBuffer (); Long begin = System.currenttimemillis (); for (int i=0; i<time; i++) {sb.append ("Java");} Long over = System.currenttimemillis (); SYSTEM.OUT.PRINTLN ("Operation" +sb.getclass (). GetName () + "type is used for:" + (Over-begin) + "MS"); }public static void Teststringbuilder () {StringBuilder sb = new StringBuilder (); Long begin = System.currenttimemillis (); for (int i=0, i<time; i++) {sb.append ("Java");} long over = System.currenttimemillis (); SYSTEM.OUT.PRINTLN ("Operation" +sb.getclass (). GetName () + "type is used for:" + (Over-begin) + "Milliseconds "); }public static void Test1string () {Long begin = System.currenttimemillis (); for (int i=0; i<time; i++) {String s = "I" + "Love" + "Java"; } Long over = System.currenttimemillis (); System.out.println ("String Direct Add Operation:" + (Over-begin) + "millisecond"); }public static void Test2string () {String S1 = "I"; String s2 = "Love"; String s3 = "Java"; Long begin = System.currenttimemillis (); for (int i=0, i<time; i++) {String s = s1+s2+s3;} Long over = System.currenttimemillis (); System.out.println ("String Indirect addition operation:" + (Over-begin) + "millisecond"); }}

Test results (WIN7,ECLIPSE,JDK6):

  

The above mentioned string+= "Hello" operation is actually automatically optimized by the JVM, see the following code:

public class Main {private static int time = 50000;public static void Main (string[] args) {teststring (); Testoptimalstring ( );} public static void TestString () {String s= "", Long begin = System.currenttimemillis (); for (int i=0; i<time; i++) {s + = "Java"; } Long over = System.currenttimemillis (); SYSTEM.OUT.PRINTLN ("Operation" +s.getclass (). GetName () + "type is used for:" + (Over-begin) + "MS"); }public static void Testoptimalstring () {String s= ""; Long begin = System.currenttimemillis (); for (int i=0; i<time; i++ {StringBuilder sb = new StringBuilder (s); Sb.append ("Java"); s=sb.tostring ();} Long over = System.currenttimemillis (); System.out.println ("Simulated JVM optimization operation time:" + (Over-begin) + "MS"); }}

Execution Result:

  

Be verified.

The following is a general explanation of the results of the above implementation:

1) for the direct addition of strings, the efficiency is very high, because the compiler determines its value, that is, the shape of "I" + "Love" + "Java"; Strings are added, and are optimized for "Ilovejava" during compilation. This can be verified by using the JAVAP-C command to decompile the generated class file.

For the indirect addition (that is, contains the string reference), the shape is like s1+s2+s3; Efficiency is lower than the direct add, because the compiler does not optimize the reference variable.

2) execution efficiency of String, StringBuilder, StringBuffer:

StringBuilder > StringBuffer > String

Of course this is relative, not necessarily in all cases.

For example, string str = "Hello" + "world" is more efficient than StringBuilder st = new StringBuilder (). Append ("Hello"). Append ("World") is higher.

Therefore, these three classes are each with pros and cons and should be used according to different circumstances:

It is recommended to use string str= "Hello" in the case of a string addition or less modification;

It is recommended to use StringBuilder when the string addition operation is large, and stringbuffer if multi-threading is used.

Four. Common questions about string and StringBuffer

Here are some common questions about string, stringbuffer, and if there are any mistakes, please understand and criticize.

1. What is the output of the following code?

String a = "Hello2";   String b = "Hello" + 2; System.out.println ((A = = b));

The output is: true. The reason is simple: "Hello" +2 has been optimized for "Hello2" during compilation, so the variable A and variable B point to the same object during run time.

2. What is the output of the following code?

String a = "Hello2";       String b = "Hello";       String C = b + 2; System.out.println ((A = = c));

The output is: false. Because of the existence of a symbolic reference, String C = B + 2, is not optimized during compilation, does not treat b+2 as a literal constant, so objects generated in this manner are actually stored on the heap. So a and C point to not the same object. What the javap-c get:

  

3. What is the output of the following code?

String a = "Hello2";       Final String b = "Hello";       String C = b + 2; System.out.println ((A = = c));

The output is: true. For a final modified variable, a copy is saved in the class file constant pool, that is, not accessed through a connection , and access to the final variable is directly substituted for the actual value during compilation. Then string c = B + 2, which is optimized during compilation: string c = "Hello" + 2; is the content of Javap-c:

  

4. The following code outputs the result:

public class Main {public static void main (string[] args) {String a = "Hello2"; final String B = Gethello (); String C = b + 2; System.out.println ((A = = c));} public static String Gethello () {return "Hello";}}

The output is false. Although the B is decorated with final, but because its assignment is returned through a method call, its value can only be determined during run time, so a and C point to not the same object.

5. What is the output of the following code?

public class Main {public static void main (string[] args) {String a = "Hello"; String b =  new string ("Hello"); String c =  new string ("Hello"); String d = B.intern (); System.out.println (A==B); System.out.println (B==C); System.out.println (B==d); System.out.println (A==d);}}

The output is (JDK version JDK6):

  

This involves the use of the String.intern method. In the string class, the Intern method is a local method, and before Java SE6, the Intern method looks for a string that has the same content in the run-time pool, returns a reference to the string if it exists, and, if it does not, the string into the pool. and returns a reference to the string. As a result, a and D point to the same object.

How many objects are created by 6.String str = new String ("abc")?

This question in a lot of books have said, such as "Java Programmer interview book", including many domestic large companies written test questions will encounter, most of the online circulation and some interview books are said to be 2 objects, this statement is one-sided.

If you do not know the place can refer to this post:

http://rednaxelafx.iteye.com/blog/774673/

The first thing you have to figure out is what created the object, and when was it created? Does this code create 2 objects during run time? There is no doubt that the bytecode content of the JVM execution can be obtained with javap-c decompile:

  

Obviously, new is called only once, which means that only one object is created.

And this is where the problem is confusing, and this code actually creates only one object during the run, that is, the "ABC" object is created on the heap. And why are we all talking about 2 objects, here to clarify a concept the code execution process and the class loading process are different. During class loading, it was true that an "ABC" object was created in the run-time pool, and indeed only one string object was created during the execution of the code.

So, if this problem is replaced by string str = new String ("abc"), how many string objects are involved? A reasonable explanation is 2.

Personally feel that in the interview if you encounter this problem, you can ask the interviewer clearly "is the code during the execution of how many objects created or how many objects" and then according to the specific answer.

7. What is the difference between the following code 1) and 2?

public class Main {public static void main (string[] args) {String str1 = ' I ';//str1 + = "Love" + "Java";        1) str1 = str1+ "Love" + "Java";      2)}}

1) is more efficient than 2, and 1) in the "Love" + "Java" will be optimized during compilation to "Lovejava", and 2) will not be optimized. Here are the two ways to bytecode:

1) The byte code:

  

2) The byte code:

  

As you can see, only one append operation was performed in 1, and two append operations were performed in 2).

Reference article: http://rednaxelafx.iteye.com/blog/774673/

Http://www.blogjava.net/Jack2007/archive/2008/06/17/208602.html

Http://www.jb51.net/article/36041.htm

http://blog.csdn.net/yirentianran/article/details/2871417

Http://www.jb51.net/article/33398.htm

Explore strings, StringBuilder, and StringBuffer in Java

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.