❤️ Detailed explanation of String, StringBuilder and StringBuffer ❤️ (with principle, test case and suggestion Collection)

1, Introduction to String class

The String class, located under the java.lang package, is the core class of the Java language. It provides String comparison, search, interception, case conversion and other operations. You can use "+" to connect other objects. Part of the source code of the String class is as follows

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
    /** 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 can be seen from the above

  1. The String class is modified by the final keyword, which means that the String class cannot be inherited, and its member methods default to the final method; Once a String is created, it cannot be modified;
  2. String class implements Serializable, CharSequence and Comparable interfaces;
  3. The value of the s tring instance is stored through the character array;

2, "+" connector

1. Implementation principle of "+" connector

String connection is realized through StringBuilder (or StringBuffer) class and its append method. Object conversion to string is realized through toString method. This method is defined by object class and can be inherited by all classes in Java.

We can verify the following by decompiling:

public class Test {
    public static void main(String[] args) {
        int i = 10;
        String s = "nezha";
        System.out.println(s + i);
    }
}
 
/**
 * After Decompilation
 */
public class Test {
    public static void main(String args[]) { 
        ...
        byte byte0 = 10;      
        String s = "nezha";      
        System.out.println((new StringBuilder()).append(s).append(byte0).toString());
    }
}

From the above code, we can see that the bottom layer of the "+" connection string is actually completed by the StringBuilder object through append and then calling toString.

2. Efficiency of "+" connector

When using the "+" connector, the JVM will implicitly create a StringBuilder object. This method will not cause efficiency loss in most cases, but it is different when splicing strings in a loop.

Because a large number of StringBuilder objects will be created in heap memory, which is certainly not allowed, it is recommended to create a StringBuilder object outside the loop, and then call the append method inside the loop for manual splicing.

In another special case, if "+" splices strings in string constants, the compiler will optimize and directly splice the two string constants.

Therefore, the "+" connector is very efficient for directly added string constants, because its value is determined during compilation; However, for indirect addition, the efficiency will become lower. It is recommended to use StringBuilder for single thread and StringBuffer for multithreading.

3, String, StringBuilder and StringBuffer

1. Main differences

  1. String is an immutable character sequence, and StringBuilder and StringBuffer are variable character sequences.
  2. Execution speed StringBuilder > StringBuffer > string.
  3. StringBuilder is non thread safe and StringBuffer is thread safe.

2. Efficiency test

import java.util.ArrayList;
import java.util.List;
import java.util.StringJoiner;

public class StringTest {

    private static void test01() {
        String str = "nezha,";
        String ret = "";
        System.out.println("+String splicing start...");
        long start = System.currentTimeMillis();
        // +The efficiency in the cycle is too low. Use 100000 tests
        for (int i = 0; i < 100000; i++) {
            ret += str;
        }
        long end = System.currentTimeMillis();
        System.out.println("+Time consuming for splicing 100000 pieces of data:"+(end-start)+"ms");//18288ms
        System.out.println("************");
    }

    private static void test02() {
        String str = "nezha,";
        StringBuilder builder = new StringBuilder();
        System.out.println("StringBuilder,String splicing start...");
        long start = System.currentTimeMillis();
        for (int i = 0; i < 10000000; i++) {
            builder.append(str);
        }
        long end = System.currentTimeMillis();
        System.out.println("StringBuilder Splicing 10 million pieces of data takes time:"+(end-start)+"ms");//168ms,173ms,239ms
        System.out.println("************");
    }

    private static void test03() {
        String str = "nezha,";
        StringBuffer buffer = new StringBuffer();
        System.out.println("StringBuffer,String splicing start...");
        long start = System.currentTimeMillis();
        for (int i = 0; i < 10000000; i++) {
            buffer.append(str);
        }
        long end = System.currentTimeMillis();
        System.out.println("StringBuffer Splicing 10 million pieces of data takes time:"+(end-start)+"ms");//527ms,343ms,398ms
        System.out.println("************");
    }

    /**
     * StringJoiner The efficiency of is significantly higher than that of List + StringJoiner
     */
    private static void test04() {
        String str = "nezha";
        StringJoiner join = new StringJoiner(",");
        System.out.println("StringJoiner,String splicing start...");

        long start = System.currentTimeMillis();
        for (int i = 0; i < 10000000; i++) {
            join.add(str);
        }
        long end = System.currentTimeMillis();
        System.out.println("StringJoiner Splicing 10 million pieces of data takes time:"+(end-start)+"ms");//184ms,316ms,243ms
        System.out.println("************");
    }

    private static void test05() {
        String str = "nezha";
        List<String> list = new ArrayList<String>();
        System.out.println("List + StringJoiner,String splicing start...");
        long start = System.currentTimeMillis();
        for (int i = 0; i < 10000000; i++) {
            list.add(str);
        }
        String ret = String.join(",", list);
        long end = System.currentTimeMillis();
        System.out.println("List + StringJoiner Splicing 10 million pieces of data takes time:"+(end-start)+"ms");//563ms,477ms,585ms
        System.out.println("************");
    }

    public static void main(String[] args) {
        test02();

    }
}

3. Console output

Summary: StringBuilder has the highest efficiency and + splicing has the lowest efficiency.

4. Source code analysis

StringBuilder source code

@Override
public StringBuilder append(char[] str) {
    super.append(str);
    return this;
}

  StringBuilder inherits the AbstractStringBuilder class

public final class StringBuilder
    extends AbstractStringBuilder
    implements java.io.Serializable, CharSequence
{
    ...
}
public AbstractStringBuilder append(String str) {
    if (str == null)
        return appendNull();
    int len = str.length();
    ensureCapacityInternal(count + len);
    str.getChars(0, len, value, count);
    count += len;
    return this;
}

append will directly copy characters to the internal character array. If the length of the character array is not enough, it will be extended.

The situation of StringBuffer is similar to that of StringBuilder, except that StringBuffer is thread safe.

4, String constant pool

1. Baidu Encyclopedia

Constant pool is used in java to save a copy of data in the compiled class file that has been determined at the compilation time. It includes constants in classes, methods and interfaces, as well as string constants, such as String s = "java"; Of course, it can also be expanded. The constants generated by the actuator will also be put into the constant pool. Therefore, it is considered that the constant pool is a special memory space of the JVM.

2. Object assignment of string

String object allocation consumes a lot of time and space, and strings are used very much. Many junior programmers will define all variables as string. I wonder if this was the case when you were young, ha ha.

In order to improve performance and reduce memory overhead, the JVM performs a series of optimizations when instantiating strings, that is, String constant pool. The JVM will first check the String constant pool. If it already exists, it will directly return the instance reference in the String constant pool. If it does not exist, it will instantiate the String and put it into the String constant pool. Due to the immutability of String, there must not be two identical strings in the constant pool.

3. Memory area

In the HotSpot VM, the String constant pool is implemented through a StringTable class, which is a Hash table. The default size length is 1009; This StringTable has only one copy in each HotSpot VM instance and is shared by all classes; The String constant consists of one character and is placed on the StringTable. It should be noted that if too many strings are put into the String Pool, the Hash conflict will be serious, resulting in a long linked list. The direct impact of a long linked list is that the performance will be greatly reduced when calling String.intern.

4. For example, it is clear at a glance

public class StringTest {
    public static void main(String[] args) {
        // 1. Create a new reference s1 to the object s1 in the heap with the value of "CSDN"
        String s1=new String("CSDN")+new String("nezha");
        // 2. Create a new reference s2 to the object s2 in the heap with the value "CSDN"
        String s2=new String("CS")+new String("DN nezha");
        // 3. Executing s1.intern() will create a new reference "CSDN Nezha" in the string constant pool, which points to the address of s1 in the heap, and a new reference s3 points to "CSDN Nezha" in the string constant pool
        String s3=s1.intern();
        // 4. Executing s2.intern() will not create a new reference in the string constant pool, because "CSDN Nezha" already exists, so only the operation of creating a new reference s4 to "CSDN Nezha" in the string constant pool is performed
        String s4=s2.intern();
        // s3 and s4 point to the "CSDN Nezha" in the string constant pool, and this "CSDN Nezha" points to the address of s1 in the heap
        System.out.println(s1==s3); // true
        System.out.println(s1==s4); // true
        // The address in the final Association heap of s3 and s4 is object s1
        System.out.println(s2 == s3);// false
        System.out.println(s2 == s4);// false
    }
}

5, intern() method

The String object declared directly in double quotation marks will be directly stored in the String constant pool. If it is not a String object declared in double quotation marks, you can use the intern method provided by String. The intern method is a native method. The intern method will query whether the current String exists from the String constant pool. If so, it will directly return the current String; If it does not exist, the current String will be put into the constant pool and returned later.

Changes to JDK1.7:

  1. Moved the String constant pool from the Perm area to the Java Heap area
  2. When using the String.intern() method, if there is an object in the heap, the reference of the object will be saved directly without re creating the object.

🔥 Contact the author, or scan the QR code of the home page and join us 🔥

Highlights of previous periods

Java learning route summary ❤️ Brick movers counter attack Java Architects ❤️ (the strongest in the whole network, recommended Collection)

❤️ After successive interview failures, I summarized 57 real interview questions ❤️, If time can go back... (with answers, suggestions)

Summary of 208 classic Java interview questions with 100000 words (with answers and suggestions)

Summary of MySql Basics (version 2021)

Summary of basic knowledge of MySql (SQL optimization)

[summary of the most complete Java framework in the whole stack] SSH, SSM, Springboot

Detailed explanation of springBoot Basics

Java design patterns: comprehensive analysis of 23 design patterns

Summary of common data structures and algorithms

[Vue basics summary 1] Introduction to Vue

[introduction to 100 day algorithm - three questions a day - Day1] middle order traversal of binary tree, sum of two numbers, integer inversion

Tags: Java

Posted on Fri, 19 Nov 2021 16:53:05 -0500 by Sk~