前言

字符串的比较是一个常见的面试题,这里总结一下常见的关于String的一些题目。

先明确一个概念:

基本数据类型之间的 == 是比较值,引用数据类型 == 比较的是地址值,equals方法比较的是值不是地址

示例一:

1
2
3
4
5
  public static void main(String[] args) {
String s2="abc";
String s3="abc";
System.out.println(s2==s3);
}

运行结果:

1
true

分析:使用 "" 创建的字符串会直接存储在常量池中,先检查常量池中有没有“abc"字符串,若没有则添加到常量池中去,并且直接指向它。所以变量s2指向的地址是常量池中的”abc"。同理,s3也指向了常量池中的同一个地址“abc"。由于s2和s3指向的是同一个地址,而”==“比较的是内存地址,所以返回true.

示例二:

1
2
3
4
5
6
  public static void main(String[] args) {
String s1="ab", s2="a"+"b", s3="a", s4="b";
String s5=s3+s4;

System.out.println(s5==s2);
}

结果:

1
false

分析:s2指向的是字符串常量,在编译期间是确定的。而s5中在字符串的“+”拼接中,有字符串引用的存在,而字符串引用的值在编译期间是无法确定的。所以s5是不存放到常量池中的,而是新建了对象。

示例三:

1
2
3
4
  public static void main(String[] args) {
String s1="ab", s2="a"+"b", s3="a", s4="b";
System.out.println(s1==s2);
}

运行结果:

1
true

分析:s2="a"+"b"会被编译器优化为s2="ab",也是字符串常量。所以s1和s2指向的是同一个常量池中的地址,所以返回true。

1
2
3
4
5
6
7
   public static void main(String[] args) {
String s1="ab", s2="abc";
String s3=s1+"c";

System.out.println(s3==s2);
System.out.println(s3.equals(s2));
}

结果:

1
2
false
true

示例四:

1
2
3
4
5
6
7
    public static void main(String[] args) {
String s1="abc";
String s2=new String("abc");
String s3=new String("abc");
System.out.println(s1==s2);
System.out.println(s2==s3);
}
1
2
false
false

分析:s2和s3均是在堆上创建了新的对象,s2的地址指向的是在堆上,s1的地址指向的是在常量池中,并不是一个地址,所以s2==s1返回false。同理s3也一样。

同理可以分析下面两个示例:

示例五:

1
2
3
4
public static void main(String[] args) {
String s1="ab", s2=new String("a")+"b";
System.out.println(s1==s2);
}

运行结果:

1
false

示例六:

1
2
3
4
  public static void main(String[] args) {
String s1="ab", s2=new String("a")+new String("b");
System.out.println(s1==s2);
}

运行结果:

1
false

总结

  1. “==”比价的是指向的内存地址;

  2. s1="abc"是直接分配在常量池,“a"+"b"也是直接分配常量池;

  3. s2=s1+"a";是重新分配内存,创建了新的对象;

  4. 凡是new关键字的地方都是重新分配内存,创建新对象;使用这种方式时,JVM创建字符串对象但不存储于字符串池。我们可以调用intern()方法将该字符串对象存储在字符串池,如果字符串池已经有了同样值的字符串,则返回引用。