开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第 2 天,点击查看活动详情
stackoverflow.com/questions/5… 在 Java 中如何比较 String?
问
我以前都是使用 == 操作符比较 String ,但是遇到了 bug ,使用 equals 解决了它。==什么时候可以用?他们的区别是什么?
答
== :比较地址是否相同
.equals():比较值是否相同
建议使用 Objects.equals()。
# Java util 包下提供的 Objects 类的静态方法
public static boolean equals(Object a, Object b) {
return (a == b) || (a != null && a.equals(b));
}
有一个额外问题是:
案例1:
String a="Test";
String b="Test";
sout(a==b) //true
案例2:
String aa="aa";
String aa1=new String("aa")
sout(aa==aa1) // false
sout(aa.equals(aa1)) //true
案例3:
String a = "a1";
String b = "a" + 1;
String c = new String("a")+1;
System.out.println(a == b);// true
System.out.println(b==c);
案例4:
String a = "ab";
String bb = "b";
String b = "a" +bb;
System.out.println(a == b);//false
案例5:
String a = "ab";
final String bb = "b";
String b = "a" +bb;
System.out.println(a == b);//true
案例1:
两个字符串常量,它们在编译期就被确定,创建 b 会先去 JVM 的 String 常量池中寻找,找到了就直接返回。所以两个地址一致。
案例2:
因为 new String() 会在堆上创建新对象,并且赋值给 aa1 。所以 aa1 不是常量池的。用 new String() 创建的字符串不是常量,不能在编译期就确定,所以 new String() 创建的字符串不放入常量池中,它们有自己的地址空间
判断是判断值是否相等,都是 aa。所以为 true。
案例3:
JVM 对于字符串常量的 "+" 号连接,将在程序编译期,JVM 就将常量字符串的"+"连接优化为连接后的值,拿 "a" +1 来说,经编译器优化后在 class 中就已经是 a1。
new String() 由于无法在编译期确定,所以创建的也是新对象。
案例4:
JVM 对于字符串引用,由于在字符串的 "+" 连接中,有字符串引用存在,而引用的值在程序编译期是无法确定的。只有在程序运行期来动态分配并将连接后的新地址赋给b。
案例5:
bb字符串加了 final 修饰,对于 final 修饰的变量,它在编译时被解析为常量值的一个本地拷贝存储到自己的常量池中或嵌入到它的字节码流中。
总结
== :比较引用(地址)
equals:比较值
日常开发建议使用: Java Util 包下的 Objects.equals(Object a,Object b) 方法。
还有就是需要注意,JVM String 常量池的问题。常量字符串可以使用 + 拼接,还是使用的常量池的值,但是引用不行,或者这个引用是调用方法返回的,也不行。但是 final 关键字除外:它可以在编译时解析为常量值的一个本地拷贝存储到自己的常量池中。