JAVA Basic String Learning Exploration

String

String is the most commonly used object in JAVA. It is such a most commonly used and common object. When you study deeply, you find that we don't really understand it very well, so let's learn it together!

Because of the immutable nature of String, Java implements a constant pool internally. When a String is created, it will first go to the constant pool to see if there are any examples with the same value, and if so, return it directly. Saves memory and speeds up the loading of strings. Immutable objects are also guaranteed to remain thread-safe in concurrency

characteristic

  • String constants, which are actually String objects
  • All Strings not created by new are placed in the constant pool
  • Objects of type String are immutable
  • String implements the CharSequence interface

How to create a String object

String str1 = "abcd";
String str2 = new String("abcd");

These two different creation methods are different. The first way is to get the object in the constant pool, and the second way is to create a new object directly in the heap memory space.
As long as you use the new method, you need to create a new object

Concatenation expression + (plus sign)

  1. Only new objects created by using "+" concatenation between String objects created by using quotation marks to contain text will be added to the string pool.
  2. For all "+" connection expressions that contain new objects (including null) in the new method, the new objects generated by it will not be added to the string pool.
String str1 = "str";
String str2 = "ing";

String str3 = "str" + "ing";
String str4 = str1 + str2;
System.out.println(str3 == str4);//false

String str5 = "string";
System.out.println(str3 == str5);//true
1、 Sting s; //定义了一个变量s,没有创建对象;
2、 =    // 赋值,将某个对象的引用(句柄)赋给s ,没有创建对象;
3、 “abc”    //创建一个对象;
4new String(); // 创建一个对象。

Common method

  • length returns the length of the string

  • isEmpty determines whether the string is empty

  • charAt gets char according to the index position

  • getChars copies the char of the corresponding position range into the array

  • equals, equalsIgnoreCase The comparison order is the reference address, the length of the char array, and the content of the char array.

  • compareTo compares string sizes

  • startsWith, endsWith judge the prefix and suffix

  • hashCode calculates the hash value, the formula is s[0]*31^(n-1) + s[1]*31^(n-2) + … + s[n-1]

  • indexOf finds the position of the first occurrence

  • lastIndexOf finds the last occurrence

  • substring returns the substring (the old version is to return a new string that references the parent string, saving reallocation of memory. But in fact, if the substring references a parent string that occupies a lot of space, the parent string will not be used because the substring has been used all the time. The method is garbage collected, and the new version of substring re-copy the char array every time)

  • concat concatenates strings (concatenates char arrays, recreates strings)

  • replace replaces all old characters with new characters (it will traverse the char array once, look for it when it exists, and then replace it to avoid allocating the char array every time)

  • matches to determine whether it conforms to the regular pattern (reuse Pattern.matches() method)

  • contains determines whether a substring is included (reuse indexOf() method)

  • replaceFirst replaces only once

  • replaceAll replaces all regular occurrences

  • split splits the string according to the regular

  • toLowerCase returns lowercase

  • toUpperCase returns uppercase

  • trim remove leading and trailing spaces

  • toCharArray re-copy the char array to return

  • join(CharSequence delimiter, CharSequence… elements)

    String.join(",", "you", "bao", "luo");
    //out: you,bao,luo
  • equals(Object anObject)

String.equals() code logic:

  1. Determine whether the incoming object and the current object are the same object, and if so, return true directly;

  2. Determine whether the incoming object is a String, if not, return false (if it is null, it does not hold);

  3. Determine whether the incoming String is the same length as the current String, if not, return false;

  4. Cyclically compare the char[] arrays of the two strings, and compare the characters one by one to see if they are consistent. If they are inconsistent, return false directly;

  5. Returns true if no mismatch is found at the end of the loop;

JDK8源码:
public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    if (anObject instanceof String) {
        String anotherString = (String)anObject;
        int n = value.length;
        if (n == anotherString.value.length) {
            char v1[] = value;
            char v2[] = anotherString.value;
            int i = 0;
            while (n-- != 0) {
                if (v1[i] != v2[i])
                    return false;
                i++;
            }
            return true;
        }
    }
    return false;
}
  • intern(): naive method, which directly returns the reference in the constant pool

When the intern() method is called, the JVM will use the equals() method to find out whether there is an equivalent String in the constant pool. If it exists, it will directly return the address of the String object in the constant pool; if it does not exist, it will create an equivalent String. String (that is, the equivalent char[] array string, but char[] is a newly created copy space), and then returns the address of this newly created space;

When looking for an equivalent String in the constant pool, there is usually not only one string but multiple strings, so the efficiency will be relatively low. In addition, in order to ensure uniqueness, a lock is required;

String str1 = "ab"
String str2 = new String("ab");
System.out.println(str1== str2);//false
System.out.println(str2.intern() == str1);//true

System.out.println(str1== str2);//false
str2 = str2.intern();
System.out.println(str1== str2);//true

Knowledge point

  • In the place where x.toString() is called, ""+x can be used instead;
  • String + concatenation operation
public static void main(String[] args) throws InterruptedException {
    String s = "a";
    String st = s + "b" + "c";
  }
javap out====>
Code:
  stack=3, locals=3, args_size=1
     0: ldc           #19                 // String a
     2: astore_1
     3: new           #21                 // class java/lang/StringBuilder
     6: dup
     7: aload_1
     8: invokestatic  #23                 // Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String;
    11: invokespecial #29                 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
    14: ldc           #32                 // String b
    16: invokevirtual #34                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
    19: ldc           #38                 // String c
    21: invokevirtual #34                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
    24: invokevirtual #40                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
    27: astore_2
    28: return
  • StringBuffer is a thread safe operation
  public synchronized StringBuffer append(String str) {
    toStringCache = null;
    super.append(str);
    return this;
  }
  • StringBuilder is not thread safe

    public StringBuilder append(String str) {
    super.append(str);
    return this;
    }
System.err.println("hello,world"); ##hello,world实际是String对象

printf formatted output

write picture description here

FAQ
1. String str1 = "abc"; System.out.println(str1 == "abc");
Steps:
a> Create a space in the stack to store the reference str1;
b> Create a space in the String pool to store String constants" abc";
c> refers to str1 to point to the String constant "abc" in the pool;
d> the address pointed to by str1 is the address of the constant "abc", and the output is true;

  1. String str2 = new String("abc"); System.out.println(str2 == "abc");
    Steps:
    a> Create a space in the stack to store the reference str2;
    b> Create a space in the heap to store a new String The object "abc";
    c> refers to str2 to point to the newly created String object "abc" in the heap;
    d> The address of the object referred to by str2 is the address in the heap, while the address of the constant "abc" is in the pool, and the output is false;
    note : For the object generated by new, it will go to the constant pool to check whether there is "abc", if not, first create an "abc" object in the constant pool, and then create a copy of the "abc" object in the constant pool in the heap object;

  2. String s2 = new String("Hello"); How many objects are produced?
    First of all, during the working process of the jvm, a memory space will be created to store the string object. We call this memory space the string pool;
    String s2 = new String("Hello"); JVM first looks in the string pool to see if it can't find the string "Hello", if found, do nothing; otherwise, create a new string object , put it in the string pool. Since new is encountered, a string object is also created on the memory heap (not in the string pool) to store "Hello", and the string object in memory (not in the string pool) is returned to s2.
    Re: If there is no "Hello" in the constant pool, create two objects. If "Hello" exists in the original constant pool, it is an object;

  3. other

String str1 = "a"String str2 = "b"String str3 = str1 + "b"//str1 和 str2 是字符串常量,所以在编译期就确定了。  
//str3 中有个 str1 是引用,所以不会在编译期确定。  
//又因为String是 final 类型的,所以在 str1 + "b" 的时候实际上是创建了一个新的对象,在把新对象的引用传给str3

final String str1 = "a"String str2 = "b"String str3 = str1 + "b"//这里和\(3\)的不同就是给 str1 加上了一个final,这样str1就变成了一个常量。  
//这样 str3 就可以在编译期中就确定了  

compile-time optimization

The compiler will superimpose fixed values ​​for string constants at compile time. String constants include "hello" or variables modified with fianl. The compiler considers these constants to be immutable.

Compiler optimizes String constant concatenation

Example 1

String str = "hello" + "java" + 1;
// 编译期编译器会直接编译为"hellojava1"
#2 = String             #21            // hellojava1
#21 = Utf8               hellojava1

Example 2

public static final String A = "ab"; // 常量A
public static final String B = "cd"; // 常量B
public static void main(String[] args) {
     String s = A + B;  // 将两个常量用+连接对s进行初始化
     String t = "abcd";   
    if (s == t) {   
         System.out.println("s等于t,它们是同一个对象");   
     } else {   
         System.out.println("s不等于t,它们不是同一个对象");   
     }   
 }
output ==> s等于t,它们是同一个对象

Explanation: Both A and B are constants, and the value is fixed, so the value of s is also fixed, which is determined when the class is compiled. That is to say: String s=A+B; is equivalent to: String s=”ab”+”cd”;

Example three

public static final String A; // 常量A
public static final String B;    // 常量B
static {   
     A = "ab";   
     B = "cd";   
 }   
 public static void main(String[] args) {   
    // 将两个常量用+连接对s进行初始化   
     String s = A + B;   
     String t = "abcd";   
    if (s == t) {   
         System.out.println("s等于t,它们是同一个对象");   
     } else {   
         System.out.println("s不等于t,它们不是同一个对象");   
     }   
 }
output ==> s不等于t,它们不是同一个对象

Although A and B are defined as constants, they are not assigned values ​​immediately. Before the value of s is calculated, when they are assigned, and what value they are assigned, are variables. So A and B behave like a variable until they are assigned a value. Then s cannot be determined at compile time, but can only be created at runtime

String addition operation in the loop

  • Less performant code:
public void  implicitUseStringBuilder(String[] values) {
  String result = "";
  for (int i = 0 ; i < values.length; i ++) {
      result += values[i];
  }
  System.out.println(result);
}

Compiled bytecode:

public void implicitUseStringBuilder(java.lang.String[]);
  Code:
     0: ldc           #11                 // String
     2: astore_2
     3: iconst_0
     4: istore_3
     5: iload_3
     6: aload_1
     7: arraylength
     8: if_icmpge     38
    11: new           #5                  // class java/lang/StringBuilder
    14: dup
    15: invokespecial #6                  // Method java/lang/StringBuilder."<init>":()V
    18: aload_2
    19: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
    22: aload_1
    23: iload_3
    24: aaload
    25: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
    28: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
    31: astore_2
    32: iinc          3, 1
    35: goto          5
    38: getstatic     #9                  // Field java/lang/System.out:Ljava/io/PrintStream;
    41: aload_2
    42: invokevirtual #10                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
    45: return

8: if_icmpge 38 and 35: goto 5 form a loop;

8: if_icmpge 38 means if (the opposite of i < values.length) holds, then jump to line 38 (System.out).

35: goto 5 means jump directly to line 5.

But one very important thing here is that the creation of StringBuilder objects occurs between loops, which means how many StringBuilder objects will be created for how many loops, which is obviously lower in performance.

  • high performance code
public void explicitUseStringBuider(String[] values) {
  StringBuilder result = new StringBuilder();
  for (int i = 0; i < values.length; i ++) {
      result.append(values[i]);
  }
}
public void explicitUseStringBuider(java.lang.String[]);
  Code:
     0: new           #5                  // class java/lang/StringBuilder
     3: dup
     4: invokespecial #6                  // Method java/lang/StringBuilder."<init>":()V
     7: astore_2
     8: iconst_0
     9: istore_3
    10: iload_3
    11: aload_1
    12: arraylength
    13: if_icmpge     30
    16: aload_2
    17: aload_1
    18: iload_3
    19: aaload
    20: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
    23: pop
    24: iinc          3, 1
    27: goto          10
    30: return

As can be seen from the above, 13: if_icmpge 30and 27: goto 10constitute a loop loop, and are 0: new #5located outside the loop, so StringBuilder will not be created multiple times.

Note: It is necessary to avoid implicit or explicit creation of StringBuilder in the loop body as much as possible

Immutable String

String objects are immutable. Every method in the String class that appears to modify a String value actually creates a brand new String object containing the modified string content

String str1 = "java";
String str2 = "java";
System.out.println\("str1=str2   " + \(str1 == str2\)\);

In code, you can create multiple aliases of the same String object, and they refer to the same object, always staying in a single physical location

Overload "+"

In Java, the only overloaded operators are "+" and "+=" for String. In addition, Java does not allow programmers to overload other operators

public class StringTest {
    String a = "abc";
    String b = "mongo";
    String info = a + b + 47;
}

String objects are immutable, so the above code process might work like this:

  1. "abc" + "mongo" creates a new String object abcmongo;
  2. "abcmongo" + "47" creates a new String object abcmongo47;
  3. Reference info points to the final generated String;

But this method will generate a lot of intermediate objects that need to be garbage collected, and the performance is quite bad

Compiler optimization processing

Compiled from "StringTest.java"
public class StringTest {
  java.lang.String a;

  java.lang.String b;

  java.lang.String info;

  public StringTest();
    Code:
       0: aload_0
       1: invokespecial #12                 // Method java/lang/Object."<init>":
()V
       4: aload_0
       5: ldc           #14                 // String abc
       7: putfield      #16                 // Field a:Ljava/lang/String;
      10: aload_0
      11: ldc           #18                 // String mongo
      13: putfield      #20                 // Field b:Ljava/lang/String;
      16: aload_0
      17: new           #22                 // class java/lang/StringBuilder
      20: dup
      21: aload_0
      22: getfield      #16                 // Field a:Ljava/lang/String;
      25: invokestatic  #24                 // Method java/lang/String.valueOf:(
Ljava/lang/Object;)Ljava/lang/String;
      28: invokespecial #30                 // Method java/lang/StringBuilder."<
init>":(Ljava/lang/String;)V
      31: aload_0
      32: getfield      #20                 // Field b:Ljava/lang/String;
      35: invokevirtual #33                 // Method java/lang/StringBuilder.ap
pend:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      38: bipush        47
      40: invokevirtual #37                 // Method java/lang/StringBuilder.ap
pend:(I)Ljava/lang/StringBuilder;
      43: invokevirtual #40                 // Method java/lang/StringBuilder.to
String:()Ljava/lang/String;
      46: putfield      #44                 // Field info:Ljava/lang/String;
      49: return
}

Decompiling the above code will find that the compiler automatically introduces the StringBuilder class.
The compiler creates a StringBuilder object, calls the StringBuilder.append() method, and finally calls toString() to generate the result, thereby avoiding the performance loss of the intermediate object

The design idea of ​​string constant pool

  • The allocation of strings, like other object allocations, consumes high time and space costs. As the most basic data type, a large number of strings are frequently created, which greatly affects the performance of the program.
  • In order to improve performance and reduce memory overhead, JVM makes some optimizations when instantiating string constants
    • Open up a string constant pool for strings, similar to a buffer area
    • When creating a string constant, first insist on whether the string exists in the string constant pool
    • If the string exists, return the reference instance, if it does not exist, instantiate the string and put it in the pool
  • basis of realization
    • The basis for this optimization is that strings are immutable and can be shared without worrying about data conflicts
    • There is a table in the global string constant pool created by the runtime instance, which always maintains a reference for each unique string object in the pool, which means that they always refer to objects in the string constant pool, so, in These strings in the constant pool will not be collected by the garbage collector
  • The benefits of the constant pool: The constant pool is to avoid the frequent creation and destruction of objects and affect the system performance, which realizes the sharing of objects. For example, the string constant pool, put all string literals into a constant pool at the compile stage;
    • Save memory space: all the same string constants in the constant pool are merged, occupying only one space;
    • Saves running time: == is faster than equals() when comparing strings. For two reference variables, only use == to determine whether the references are equal, and then you can determine whether the actual values ​​are equal

String constant pool storage location

The string constant pool exists in the method area

String str1 = “abc”;
String str2 = “abc”;
String str3 = “abc”;
String str4 = new String(“abc”);
String str5 = new String(“abc”);

write picture description here

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

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325674488&siteId=291194637
Recommended