This article will take a look at 5 interview questions about theJava String
category. These five questions, I myself asked during the interview process I have personally experienced several questions, and this article will help you understand why the answers to these questions are what they are.
public class Demo2_String { public static void main(String[] args) { String st1 = "abc"; String st2 = "abc"; System.out.println(st1 == st2); System.out.println(st1.equals(st2)); } }
Output result:
Analysis
First look at the first print statement. In Java, the symbol==
is Comparison operator, it can determine whether the basic data type and reference data type are equal. If it is a basic data type,==
compares whether the values are equal. If it is a reference data type,==
The comparison is whether the memory addresses of the two objects are equal.
Strings do not belong to the 8 basic data types. String objects belong to reference data types. In the above, "abc" is assigned to two string objects st1 and st2 at the same time, pointing to the same address. , so the == comparison output result in the first print statement is true Then we look at the comparison of equals in the second print statement. We know that equals is a method of the parent class Object, and this equals method is rewritten in the String class.
在JDK API 1.6文档中找到String类下的equals方法,点击进去可以看到这么一句话“将此字符串与指定的对象比较。当且仅当该参数不为null,并且是与此对象表示相同字符序列的String 对象时,结果才为 true。” 注意这个相同字符序列,在后面介绍的比较两个数组,列表,字典是否相等,都是这个逻辑去写代码实现。
由于st1和st2的值都是“abc”,两者指向同一个对象,当前字符序列相同,所以第二行打印结果也为true。下面我们来画一个内存图来表示上面的代码,看起来更加有说服力。
内存过程大致如下:
1)运行先编译,然后当前类Demo2_String.class文件加载进入内存的方法区
2)第二步,main方法压入栈内存
3)常量池创建一个“abc”对象,产生一个内存地址
4)然后把“abc”内存地址赋值给main方法里的成员变量st1,这个时候st1根据内存地址,指向了常量池中的“abc”。
5)前面一篇提到,常量池有这个特点,如果发现已经存在,就不在创建重复的对象
6)运行到代码 Stringst2 =”abc”, 由于常量池存在“abc”,所以不会再创建,直接把“abc”内存地址赋值给了st2
7)最后st1和st2都指向了内存中同一个地址,所以两者是完全相同的。
String st1 = new String(“abc”);
答案是:在内存中创建两个对象,一个在堆内存,一个在常量池,堆内存对象是常量池对象的一个拷贝副本。
分析
我们下面直接来一个内存图。
当我们看到了new这个关键字,就要想到,new出来的对象都是存储在堆内存。然后我们来解释堆中对象为什么是常量池的对象的拷贝副本。
“abc”属于字符串,字符串属于常量,所以应该在常量池中创建,所以第一个创建的对象就是在常量池里的“abc”。
第二个对象在堆内存为啥是一个拷贝的副本呢,这个就需要在JDK API 1.6找到String(String original)这个构造方法的注释:初始化一个新创建的 String 对象,使其表示一个与参数相同的字符序列;换句话说,新创建的字符串是该参数字符串的副本。所以,答案就出来了,两个对象。
package string; public class Demo2_String { public static void main(String[] args) { String st1 = new String("abc"); String st2 = "abc"; System.out.println(st1 == st2); System.out.println(st1.equals(st2)); } }
答案:false 和 true 由于有前面两道题目内存分析的经验和理论,所以,我能快速得出上面的答案。
==比较的st1和st2对象的内存地址,由于st1指向的是堆内存的地址,st2看到“abc”已经在常量池存在,就不会再新建,所以st2指向了常量池的内存地址,所以==判断结果输出false,两者不相等。
第二个equals比较,比较是两个字符串序列是否相等,由于就一个“abc”,所以完全相等。
内存图如下
public class Demo2_String { public static void main(String[] args) { String st1 = "a" + "b" + "c"; String st2 = "abc"; System.out.println(st1 == st2); System.out.println(st1.equals(st2)); } }
答案是:true 和 true 分析:“a”,”b”,”c”三个本来就是字符串常量,进行+符号拼接之后变成了“abc”,“abc”本身就是字符串常量(Java中有常量优化机制),所以常量池立马会创建一个“abc”的字符串常量对象,在进行st2=”abc”,这个时候,常量池存在“abc”,所以不再创建。所以,不管比较内存地址还是比较字符串序列,都相等。
public class Demo2_String { public static void main(String[] args) { String st1 = "ab"; String st2 = "abc"; String st3 = st1 + "c"; System.out.println(st2 == st3); System.out.println(st2.equals(st3)); } }
答案:
false
true
Analysis
The first answer above is false, the second is true, and the second is true. We can understand it easily, because one of the comparisons is "abc" and the other is the spliced " abc", so equals comparison, this outputs true, which we understand easily.
So why the first judgment is false, we are confused. Similarly, below we use API comments and memory diagrams to explain why this is not equal.
First of all, open the introduction of String in JDK API 1.6 and find the sentence in the picture below.
The key point is the sentence in the red circle. We know that any data and string are subjected to the plus sign ( ) operation, and the final result is a spliced new string. What exactly did the number operation do? Recommended to read.
The above comments explain that the principle of this splicing is that the StringBuilder or StringBuffer class and the append method inside implement splicing, and then call toString() to convert the spliced object into a string object, and finally convert the resulting string object The address is assigned to the variable. Based on this understanding, let's draw a memory diagram for analysis.
About memory process
1) The constant pool creates the "ab" object and assigns it to st1, so st1 points to "ab"
2) The constant pool creates the "abc" object and assigns it to st2, so st2 points to "abc"
3) Due to the splicing method used here, the third step is to use the append of the StringBuffer class Method, "abc" is obtained. At this time, memory 0x0011 represents a StringBuffer object. Note that it is not a String object.
4) Call the toString method of Object to replace the StringBuffer object with a String object.
5) Assign the String object (0x0022) to st3
So, the == judgment result of st3 and st2 is not equal because the memory addresses of the two objects are different.
This interview question is completely required to master some annotations and principles in the JDK API, as well as memory graph analysis , to get the correct result. I admit that drawing the memory diagram helped me understand why the answer is like this.
The above is the detailed content of 5 String interview questions, less than 10% of people can answer them all correctly! (with answer). For more information, please follow other related articles on the PHP Chinese website!