Java中对于对象引用类型, ”==“ 比较的是对象的内存地址。String类型用到了常量池,在创建对象时就有了常量和变量之分。以下总结记录字符串使用 == 比较的一些情况。

1. 使用常量定义和new一个对象

最基础的一种情况, str1 str2都在常量池,内存地址是相等的,是同一个对象。str3 和 str4 都是new出来的对象,使用new每次都会创建新对象。

1
2
3
4
5
6
7
8
9
10
String str1 = "hello";
String str2 = "hello";
String str3 = new String("hello");
String str4 = new String("hello");
// true 都在常量池
System.out.println(str1 == str2);
// false 使用了 new 关键字,所以会在堆空间中开辟一块内存区域,在其中存放字符串 123,并把内存的地址赋予 b 变量
System.out.println(str1 == str3);
// false
System.out.println(str3 == str4);

2. + 表达式

可以把常量池的字符串理解为常量,对象的引用当成变量。

2.1 变量拼接

对象间的相加不会添加到常量池,s3和s4是不同的对象

1
2
3
4
5
6
String s1 = "1";
String s2 = "1";
String s3 = "11";
String s4 = s1 + s2;
// false
System.out.println(s3 == s4);
2.2 变量常量拼接

假如把s4 = s1 + s2 改成 s4 = s1 + “1”, s3 ==s4 仍是false。

1
2
3
4
5
String s1 = "1";
String s3 = "11";
String s4 = s1 + "1";
// false
System.out.println(s3 == s4);
2.3 常量拼接

假如把s4 = s1 + s2 改成 s4 = “1” + “1”, s3 ==s4 就是true了,常量字符串间的 “+” 会把结果加入到常量池。

1
2
3
4
String s3 = "11";
String s4 = "1" + "1";
// true
System.out.println(s3 == s4);
2.4 final修饰的字符串是常量

既然常量字符串间的 “+” 会把结果加入到常量池,那用final修饰字符串结果会如何呢?

2.3中结果是false,但是s1加上了final修饰, 结果是true。

1
2
3
4
5
final String s1 = "1";
String s3 = "11";
String s4 = s1 + "1";
// true
System.out.println(s3 == s4);

这里要注意以下是不相等的. m1是常量,不是”q”在常量池里面。

1
2
3
4
final String m1 = new String("q");
String m2 = "q";
// false
System.out.println(m1 == m2);

3. static修饰

STRING1 2 3 4都是同一个对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public static final String STRING1;
public static final String STRING2;
public static final String STRING3 = "a";
public static final String STRING4 = "a";

static {
STRING1 = "a";
STRING2 = "a";
}
public static void main(String[] args) {
// true
System.out.println("static " + (STRING1 == STRING2));
// true
System.out.println("static " + (STRING3 == STRING4));
// true
System.out.println("static " + (STRING1 == STRING3));

}

static包裹的代码是静态代码块,STRING1+STRING2在编译期不能决定

1
2
3
4
5
String ele = "aa";
//false
System.out.println(ele == STRING1 + STRING2);
// true
System.out.println(ele == STRING3 + STRING4);

4. String.intern()

String.intern() 是一个 Native 方法,如果运行时常量池中已经包含一个等于此 String 对象内容的字符串,则返回常量池中该字符串的引用;如果没有,则在常量池中创建与此 String 内容相同的字符串,并返回常量池中创建的字符串的引用。

1
2
3
4
5
6
7
8

String newStr1 = new String("计算机");
String newStr2 = newStr1.intern();
String newStr3 = "计算机";
// false,因为一个是堆内存中的String对象一个是常量池中的String对象,
System.out.println(newStr1 == newStr2);
// true,因为两个都是常量池中的String对象
System.out.println(newStr3 == newStr2);