🎈 基本数据类型使用关系运算符(== != < > <= >=)比较的是数值;
🎈引用类型间使用关系运算符(== != < > <= >=)比较的是地址;
🎈String类型在堆中存储时,其底层设置了一个字符串常量池,本质是一个哈希表。
1.无拼接的比较
🎯实例1:字符串常量的直接赋值与构造
public static void main(String[] args) {
String s1 = "hello";
String s2 = "hello";
String s3 = new String("hello");
String s4 = new String("hello");
System.out.println(s1 == s2); // true
System.out.println(s1 == s3); // false
System.out.println(s3 == s4); // false
}
-
直接使用字符串常量进行赋值,这会先将字符串常量哈希到对应位置,对于相同的字符串常量会直接从字符串常量池中引用,所以s1和s2的地址是相同的。
-
直接实例化new String(num)也是会先在常量池中映射,pool中有则不用创建,没有则创建,然后他都会直接在堆区重新开辟一块空间然后指向存在的字符串地址。虽然新的空间内部和哈希表有相同的指向,但是新空间的地址还是新地址所以s1和s3,s3和s4不同。
-
这个和包装类的缓存区类似,在缓存区范围内就会直接引用,这样的操作都是为了节省空间。
2.有拼接的比较
🎯实例二:字符串拼接
public static void main(String[] args) {
String a = "abc";
String b = "a" + "bc"; // 字符串常量间拼接
String temp1 = "a";
String c = temp1 + "bc"; // 字符串变量与字符串常量拼接
String d = "a" + new String("bc");// 字符串变量与字符串常量拼接,只是这个变量没有名字
String temp2 = "bc";
String e = temp1 + temp2;// 字符串变量与字符串变量拼接
System.out.println(a == b);
System.out.println(a == c);
System.out.println(a == d);
System.out.println(a == e);
}
📢结果:
true
false
false
false
✍ 分析:在控制台查看编译结果
💡console编译查看:
String a = "abc";
String b = "a" + "bc"; // 字符串常量间拼接
📌当字符串常量之间直接拼接时,编译器直接会优化成拼接结果,即String b = “a” + “bc"编译时就转变为了"abc”,然后继续下面其他操作。
💡console编译查看:
String temp1 = "a";
String c = temp1 + "bc"; // 字符串变量与字符串常量拼接
String d = "a" + new String("bc");// 字符串变量与字符串常量拼接,只是这个变量没有名字
String temp2 = "bc";
String e = temp1 + temp2;// 字符串变量与字符串变量拼接
📌当字符串变量与字符串常量拼接和字符串变量与字符串变量拼接时,其实底层调用了StringBuilder来拼接,拼接完会toString。
🎯再看StringBuilder的toString方法:
public String toString() {
// Create a copy, don't share the array
return new String(value, 0, count);
}
所以产生一个新的对象。
3.总结
- 无拼接的比较就看new了没,有new那么就是唯一,就是不等。
- 有拼接的分为
- 字符串常量之间的拼接,编译器直接优化成一个字符串,所以如果字符串内容是相等则相等
- 一旦有字符串变量,那么编译器就会使用StringBuilder来拼接,然后toString转为新的字符串,也即是唯一的