关于 == 和 equals 使用的一些问题

举报
cloud昵称bbs 发表于 2021/06/23 09:58:41 2021/06/23
【摘要】 StringBuffer 的 `==` 和 `equals` `StringBuilder` 的 `==` 和 `equals` `String` 的 `==` 和 `equals` `concat()` 和 `+` 的区别 intern()

问题1

StringBuffer 的 ==equals

public class A {
    public static void main(String[] args) {
        StringBuffer s1 = new StringBuffer("abc");
        StringBuffer s1 = new StringBuffer("abc");
        System.out.println(s1.equals(s2));  // false
        System.out.println(s1==s2);      // false
    }
}

两个输出结果都是 false
== 比较2个对象是否占用同一个物理地址,如果是占用同一个物理地址的话,就是说这两个对象是同一个对象,返回值为 true;如果不是占用同一个物理地址的话,就返回 false;
StringBuffer 由于没有重写 equals 方法,所以还是使用的 Objectequals 方法。对比的是两个对象的地址是否相等,等同 ==

StringBuilderStringBuffer 一样

问题2

String==equals

= 直接创建的 String 字符串存储在公共池中,而 new 创建的字符串对象在堆上

String s1 = "hello";              // String 直接创建
String s2 = "hello";              // String 直接创建
String s3 = s1;                    // 相同引用
String s4 = new String("hello");   // String 对象创建
String s5 = new String("hello");   // String 对象创建

直接使用 String :

对于储存在常量池中的字符串常量,在 String 对象和引用绑定时,JVM 在运行时,会先在常量池查找是否存在相同的字面常量;
如果存在,则直接将引用指向已经存在的字面常量;否则,在运行时,常量池开辟一个空间来存储该字面常量,并将引用指向该字面常量

使用 new :

通过 new 关键字来生成对象是在堆区进行的,而在堆区进行对象生成时,不会检测该对象是否存在
因此,通过 new 来创建对象,创建出的一定是不同的对象,即使字符串的内容是一样的

重点:
== 比较的是两个对象的地址值,对于分别处于常量池和堆中的字符串,一定不等
String 类中重写了 equals() 方法用于比较两个字符串的内容是否相等
equals() 比较的是字面值,对于分别处于常量池和堆中的字符串,可以相等

String s1 = "Hello";              // String 直接创建
String s2 = "Hello";              // String 直接创建
String s3 = s1;                   // 相同引用
String s4 = new String("Hello");  // String 对象创建
String s5 = new String("Hello");  // String 对象创建
 
s1 == s1;         // true, 相同引用
s1 == s2;         // true, s1 和 s2 都在公共池中,引用相同
s1 == s3;         // true, s3 与 s1 引用相同
s1 == s4;         // false, 不同引用地址
s4 == s5;         // false, 堆中不同引用地址
 
s1.equals(s3);    // true, 相同内容
s1.equals(s4);    // true, 相同内容
s4.equals(s5);    // true, 相同内容

问题3

concat()+ 的区别

pubic class Demo{
    pulic satic void main(String[] args){
        String str1 = "a".concat("b").concat("c")String str2 = "a"+"b"+"c";
        String str3 = "abc";
        String str4 = new String("abc");
        System.out.println(str1 == str2); //运行结果为false
        System.out.println(str1 == str3); //运行结果为false
        System.out.println(str2 == str3); //运行结果为ture
        System.out.println(str2 == str4); //运行结果为false
        System.out.println(str1.equals(str4)); //运行结果为true
    }
}

== 比较的是两个对象的地址值,equals() 比较的是字面值

那么 concat() 方法和 + 号的区别在这里有体现了,查看 concat 方法的源码可以看到,它是先复制数组,再通过 char 数组进行拼接生成一个新的对象,所以地址值会有变动,而 + 号不会

问题4

intern()

返回字符串对象的规范化表示形式。

  • 对于任意两个字符串 st ,当且仅当 s.equals(t)true 时,s.intern()==t.intern() 才为 true
public class Test {
    public static void main(String args[]) {
        String Str1 = new String("hello");
        String Str2 = new String("HELLO");

        System.out.println("规范表示:" );
        System.out.println(Str1.intern()); // hello
        System.out.println(Str2.intern());  // HELLO
        
        System.out.println("深入研究");
        String str1 = "a";
        String str2 = "b";
        String str3 = "ab";
        tring str4 = str1 + str2;
        tring str5 = new String("ab");
        
        System.out.println(str5.equals(str3));  // true
        System.out.println(str5 == str3);      // false
        System.out.println(str5.intern() == str3);   // true
        System.out.println(str5.intern() == str4);   // false
    }
}
  1. str5.equals(str3) 这个结果为 true,不用太多的解释,因为字符串的值的内容相同。

  2. str5 == str3 对比的是引用的地址是否相同,由于 str5 采用 new String 方式定义的,所以地址引用一定不相等。所以结果为 false

  3. str5 调用 intern 的时候,会检查字符串池中是否含有该字符串。由于之前定义的 str3 已经进入字符串池中,所以会得到相同的引用。

  4. str4 = str1 + str2 后,str4 的值也为 ”ab”,但是因为是变量相加,所以不会进入字符串池

对于第四个结果,可以通过代码展示原因

String a = new String("ab");
String b = new String("ab");
String c = "ab";
String d = "a" + "b";
String e = "b";
String f = "a" + e;

System.out.println(b.intern() == a);  // false
System.out.println(b.intern() == c);  // true
System.out.println(b.intern() == d);  // true
System.out.println(b.intern() == f);  // false
System.out.println(b.intern() == a.intern());  // true

由运行结果可以看出来,b.intern() == ab.intern() == c 可知,采用 new 创建的字符串对象不进入字符串池

通过 b.intern() == db.intern() == f 可知,字符串相加的时候,都是静态字符串的结果会添加到字符串池,如果其中含有变量(如 f 中的 e )则不会进入字符串池中。

但是字符串一旦进入字符串池中,就会先查找池中有无此对象。如果有此对象,则让对象引用指向此对象。如果无此对象,则先创建此对象,再让对象引用指向此对象。

String a = "abc";
String b = "abc";
String c = "a" + "b" + "c";
String d = "a" + "bc";
String e = "ab" + "c";

// 以下结果均为 true
System.out.println(a == b);
System.out.println(a == c);
System.out.println(a == d);
System.out.println(a == e);
System.out.println(c == d);
System.out.println(c == e);

如果赋值的是静态的字符串,就会执行进入字符串池的操作,如果池中含有该字符串,则返回引用。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。