String interview questions

I'm about to face an interview soon, and I'm also preparing for some interviews recently. If I don't summarize it, it's always bad. The understanding is not deep, and the writing is not good, so I can write it for myself.

Today, let's talk about String, StringBuffer, StringBuilder.

    Through the API, we know that the String class is a final class and cannot be inherited; the methods in the class are also final; the substring, replace and other methods in the class all generate a new String object, and the original object has not been changed. In fact, Any operation on the String object will not change the original object, at most will only generate a new object.

    As a newbie: The difference between String str1="hello"; and String str2=new String("hello"):

    The first way, in the jvm, there will be a string constant pool to store this string, and when another string is assigned, the virtual machine will go to the constant pool to check whether there is a constant value equal to the constant value to be assigned. Constant, if there is, point the newly defined constant to the existing constant value, if not, create another space for placing the newly defined constant. That is: String str3="hello", str1==str3 is true;

    The second way is to generate a new object and save it in the heap. Suppose the definition of String str4=new String("hello"); str4==str2 returns false, because it will only compare whether the two are the same object, and it has nothing to do with its own value.

    Another, StringBuilder, the role of StringBuffer.

Why use Stringbuilder and buffer?

We can use the following example to elicit

 

String string =  "" ;
for(int i=0;i<10000;i++){
    string+=i;
}


StringBuilder sb=new StringBuilder();
for(int i=-;i<10000;i++)
{
sb.append("hello");
}

Adding System.nanoTime() before and after can see the difference in execution efficiency between the two. Obviously, StringBuilder is more efficient, and it is not a problem of several times.

Decompile the bytecode file to see

     5: iload_2
       6: sipush        1000
       9: if_icmpge     37
      12: new           #3                  // class java/lang/StringBuilder
      15: dup
      16: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V
      19: aload_1
  20: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      23: iload_2
      24: invokevirtual #6                  // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
      27: invokevirtual #7                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      30: astore_1
      31: iinc          2, 1
      34: goto          5

, string+=i; is optimized by jvm into

StringBuilder str = new StringBuilder(string);

str.append(I);

str.toString();

    As mentioned above, any changes to String will not change the original object, but only generate new objects. Therefore, he essentially takes out the object pointed to by the original string, splices it with I, and generates another object. Points to the newly generated object. The new StringBuilder is carried out in a loop, that is, to new 1000 objects.

You can see it by decompiling the class file of StringBuilder.

       14: if_icmpge     30
       17: aload_1
       18: ldc           #4                  // String hello
  20: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      

In 1000 loops, no new objects come out, only a StringBuilder defined outside the loop, and only append in the loop body, which saves a lot of efficiency.


     The difference between StringBuilder and StringBuffer:

    Looking at the source code and comparing, you will find that they are almost the same, the only difference is that the synchronized keyword is added to StringBuffer, which means that StringBuffer is thread-safe. Safety and efficiency have always been two mutually exclusive factors in program development, and relative safety means relative inefficiency. In general, StringBuffer is less efficient than StringBuilder. Both are more efficient than the direct addition of strings.

Of course, this is not absolute. When splicing a large amount of data, the efficiency of the two is higher than the direct addition of String, but when the data is small, such as String a="hello"+"world" and StringBuilder b=new StringBuilder("hello ").append("world") compared to . The former is more efficient, if you don't believe me, try it. .

When comparing the above two loops, I used two, one is str+=i, the other is str.append("hello"); one is for constants, the other is for variables, then the constants are added directly What's the difference between adding a variable and adding it? 

The jvm is automatically optimized, we know that. For example, str = "hello" + "world"; str1 = "hello"; str2 = "world"; str3 = str1 + str2;

When the program is compiled, str has become helloworld, and str3 is the addition of two variables, which will only be assigned during runtime; therefore, the efficiency of the latter is lower than that of the former.

One question: does str==str3 return true or false? obviously, false;

Because "==" only compares whether the left and right sides are the same object, and does not care whether their addresses and values ​​are the same. str is an object placed in the constant pool, and str3 will create an object in the heap at runtime because it references another object, even if the hashcode and value of the two are equal, but they are not the same object.


Another question:

public static void main(String[] args) {
  StringBuffer s1=new StringBuffer("Hello");
  StringBuffer s2=new StringBuffer("Hello");
    System.out.println("s1方法之前:"+s1.hashCode()+"    s2: "+s2.hashCode());
    changestring(s1,s2);
    System.out.println("s1: "+s1);
    System.out.println("s2: "+s2);
}

private static void changestring(StringBuffer ss1, StringBuffer ss2) {
    System.out .println ( "Before ss1 method assignment:" + ss1.hashCode ()+ " ss2: " +ss2.hashCode());
    System.out.println("ss1:"+ss1+"    ss2: "+ss2);
    ss1.append("world");
    ss2=ss1;
    System.out .println ( "After the assignment of the ss1 method:" + ss1.hashCode ()+ " ss22222: " +ss2.hashCode());
    System.out.println("ss11111:"+ss1+"    ss22222: "+ss2);
}

How to output?


Before s1 method: 356573597 s2: 1735600054 Before
ss1 method assignment: 356573597 ss2: 1735600054
ss1: Hello ss2: Hello
After ss1 method assignment: 356573597 ss22222 :
356573597

s2: Hello


重点在于:s1可以理解,但ss2的地址值变为ss1的,值也和s1相等,而s2没有改变

为啥?

在调用changestring的时候,传递的参数是两个对象的引用,也就是地址值,ss1.append()会改变ss1指向的字符串的值,相应的也就是改变了s1指向的地址的值。

ss2=ss1这一步,改变了ss2指向的地址,相当于一个新的对象,而s2指向的地址没有改变,所以对s2没有任何影响;


好吧,先说这么多了。不知道过些日子回头看看什么样,有人看到错误,不同见解请指出,笔者正在学习路上行走。。

Guess you like

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