全面解读 == 和 equals

前言

    在Java中,==和equals都是判断是否相等的,返回值也都是Boolean类型,但是 == 和 equals 判断的内容是不一样的。

== 比较的是值

    1. 基本数据类型的比较:比较的是数值。

    2. 引用类型的比较:比较的是引用指向的值(地址)

    注:Java中没有指针的概念,只有引用。

equals 比较的是地址或者内容

    equals默认比较的也是地址,这个equals方法是Object类的方法;我们可以看一下Java源码:

See Also:
equals(Object), System.identityHashCode   
 public boolean equals(Object obj) {
        return (this == obj);
    }

    this代表当前对象的引用,也就是说谁调用equals方法谁就是this,obj是参数,可以看到Object类还是用 == 来比较两个对象的,所以Object类的equals方法还是比较的地址的值(在引用比较的过程中。

    所以在自定义的类中,如果需要比较的是内容,此时就需要学String类,重写equals方法,写定比较规则之后,自定义类才能比较引用对象的内容。

测试你是否真正了解 == 和 equals 方法的区别:

public static void main(String[] args) {
        String s1 = new String("ja");
        String s2 = new String("ja");
        System.out.println(s1 == s2);//false
        String s3 = "ja";
        String s4 = "ja";
        System.out.println(s3 == s4);//true
        System.out.println(s3 == s1);//false
        String s5 = "jaja";
        String s6 = s3 + s4;
        System.out.println(s5 == s6);//false
        final String s7 = "ja";
        final String s8 = "ja";
        String s9 = s7 + s8;
        System.out.println(s5 == s9);//true

        String s10 = "ja" + "ja";
        System.out.println(s5 == s10);//true
    }

   解析:

第一个输出:

    因为s1和s2都是new了两个对象,new对象的时候会在内存中开辟两块不同的空间,== 如果比较的是引用,此时比较的是对象的地址是否想同,输出false。

 第二个输出: 

    s3和s4两个引用都没有new对象,都是赋值了一个字符串常量,我们都知道字符串的不可变性,是因为字符串字面常量是放在字符串常量池中的,所以在赋值操作的过程,jvm先去看常量池中是否有这个对象,如果没有,就在常量池中创建 "ja" 这个字符串常量。   再等s4赋值时,此时就先去常量池中检查是否有这个字符串,如果有就不会再创建这个字符串了,直接让s4指向s3这个引用所指向的地址,所以此时s3和s4两个引用所指向的是同一个地址,输出true。

  第三个输出:

    s3引用的字符串在常量池中,s1是new了一个对象,开辟了新的空间,所以此时两个地址是不同的,输出false。

 第四个输出:

    s6引用指向的是s3 和 s4 两个字符串的拼接,s3 和 s4 是变量,虽然指向的字符串常量是放在常量池中的,但是s3 和 s4 两个引用的指向是随时可以改变的,而且字符串引用的拼接:我们可以看一下反编译的源码,String对于字符串的拼接底层是调用了StringBuilder 类中的方法的,会new一个新的StringBuilder对象,然后调用StringBuilder类中的append方法对字符串进行拼接,产生了新的对象,而s5指向的是字符串常量,在常量池中存放,两个引用的地址一定是不一样的,输出false。

 第五个输出:

    s7和s8两个引用是被final修饰的,被final修饰的变量是常量,也就是不可改变的量,此时编译器就会做出优化:在编译时期就把s7 和 s8 两个常量进行拼接,在运行之后 s9行代码和s5行代码是一样的,s5所指向的对象是放在常量池中的,s9同样也会指向这个对象,所以s5 和s9地址的值是一样的, 输出true。

第六个输出:

    s10同样的是字符串字面常量进行拼接,所以在编译时期就会将两个字符串进行拼接,在运行时和s5行代码是一样的,所以输出 true。

总结

1. 如果是常量引用的字符串字面常量进行拼接,编译器会做出优化:在编译时期就将字符串拼接的工作完成。
2. 如果是变量引用的字符串字面常量,虽然字符串是常量,但是引用的指向是可以发生改变的,所以编译器不确定引用的指向是否会发生改变,此时编译器不会做出优化。
3. 上述代码如果用equals方法进行比较,输出的结果都是true,因为String类重写了equals方法,所以比较的是地址中的内容。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

良月初十♧

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值