JavaSE中==和equals使用

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JavaSE中==和equals使用相关的知识,希望对你有一定的参考价值。

之所以写这篇博客,是因为在学习JavaSE的时候遇到了一个问题,由解决问题延伸到该类问题的总结,大概讲讲解决这个问题的思路:


首先先说说“ == ”吧,java中的“==”表示比较值。对基本数据类型来说,“==”就是比的值,这没有什么疑问;主要说的就是对于引用数据类型“==”比较的就不是对象的值了,而是对象的地址!!!

这似乎也没有什么可以说的,但是,对于引用类型中的包装类而言,由于他们具有自动装箱和自动拆箱的特点,使得初学的时候对使用“==”来比较两个包装类是否相等很是迷惑!接下来就对所有的包装类和String类做一个详细的比较和说明!先讨论的是包装类中的非new创建对象!


  1. Byte的“==”比较


    测试源代码

public class ByteBoxing {
    public static void main(String[] args) {
        //byte取值范围-128~127
        Byte b = 1;
        Byte b1 = 1;
        System.out.println(b == b1);//测试结果为true
        Byte b2 = 120;
        Byte b3 = 120;
        System.out.println(b2 == b3);//测试结果为true
    }
}


    

    测试发现:b=b1,也就是说b和b1指向的是同一个对象!原因是什么呢?如下是Byte类的源码中的截图部分:

    技术分享

    从截图看出,Byte类型在类加载的时候会自动生成一个大小是256个的Byte的常量对象,就是说这256个对象是一直不会改变的,而且其中的值是从-128到+127!这也就说明Byte类型是有缓存的!缓存是值是-128到127的256个对象!而在创建b的时候先去堆中找缓存的对象,看看是否有和b值相等的对象,如果有的话,就把这个缓存对象的地址个b。所以当使用上述代码创建对象的时候,都会先去找缓存对象,如果没有相等的话,就再在堆中开辟一个对象出来!所以只要是b的值在-128到127之间,那么就不用开辟对象了,直接把已经有的缓存对象的地址给要引用的变量就可以了。这就导致了b1操作的时候,去找缓存对象,发现已经有缓存对象了,就把该缓存对象的地址赋给b1。这就是b == b1的结果是true了!




2. Short的“==”比较


    测试源码:

public class ShortBoxing {    
  public static void main(String[] args) {
    Short s = 1;
    Short s1 = 1;
    System.out.println(s == s1);//执行结果为true   @1
    Short s2 = 150;
    Short s3 = 150;
    System.out.println(s2 == s3);  //执行结果为false   @2
  }
}


     发现 @2的结果是flase。这有点迷惑啊,不用慌,我们去看看Short的源代码是怎么设计的

技术分享     

    从图中我们看到,Short类型的源代码中也设计了256个缓存对象,值也是-128到127,所以只要Short要创建的对象的值在这个区间内,那就不必再开辟新的空间了,直接把缓存对象的地址给引用变量就可以了!所以使用“==”比较的时候,就会相等;但是值超过了缓存的值的范围,那么就只有new一个新的对象出来了,这时候(只要是new出来的对象)使用“==”就不相同了!



3. Integer类型的“==”比较


    测试源码:

    

public class IntegerBoxing {    
    public static void main(String[] args) {
        Integer i = 1;
        Integer i1 = 1;
        System.out.println(i = i1);//答案是 : true
    }
}

    从Byte和Short的解决思路上来说,我们先去看看java中的Integer的源码设计,有没有缓存,有的话,缓存大小是多大,值又是多少!下面是截图

技术分享






4. Long类型的“==”比较


    测试源码:

public class LongBoxing {
    public static void main(String[] args) {
        Long m = 2l;
        Long n = 2l;
        System.out.println(m == n);//结果是: true
    }
}

    一样的思路,去看Long的源代码设计,如下图

技术分享




同样的,Long还是和Integer,Byte一样拥有256个缓存对象,值是-128到127!


5. Float类型,Double类型


    测试源码:

public class FloatBoxing {
    public static void main(String[] args) {
        Float f = 12f;
        Float f1 = 12 f;
        System.out.println(f == f1); //!!!结果是false
    }
}

public class DoubleBoxing {
    public static void main(String[] args) {
        Double d = 1.0;
        Double d1 = 1.0;
        System.out.println(d == d1); //!!!结果是false
    }
}


从图中看出就算float和double的值在-128到127区间中,结果也是false,难道java中Flaot和 Double的源码设计和整数型的包装类不同吗?那我们就去看看源码,到底是怎么一回事

    !!!查看了Float和Double的源代码,确实里面没有缓存设计!!!这要注意和前面的区分了


6.Character类型“==”

    测试源码:

public class CharacterBoxing {
    public static void main(String[] args) {
        Character c = ‘ ‘;  //空字符,对应asscii码值是 0
        Character c1= ‘ ‘;
        System.out.println(c == c1); //结果是true
    }
}

    从测试结果看出,Character是有缓存的,我们这就去看看源代码的设计

技术分享


    从源码看出,Character是有128个缓存的,值是0~128,(具体的符号需要对应asscii码表)



7.Boolean类型“==”

    测试源码

public class BooleanBoxing {
    public static void main(String[] args) {
        Boolean b = false;
        Boolean b1 = false;
        System.out.println(b == b1);//测试结果: true
    }
}


    测试代码看出的是: Boolean也可能存在缓存,我们去看看Boolean的源代码设计中是否有缓存设计

    技术分享



8. String类型“==”

    测试源码

public class StringBoxing {
    public static void main(String[] args) {
        String s  = "hello";
        String s1 = "hello";
        System.out.println(s == s1);//结果是true
    }
}

    这个测试结果看出的是,String有可能是有缓存设计的,我们这就去看看String的源码

    技术分享



================

好了,到这儿我们就把String类和包装类的缓存设计带来的“==”问题解决完了。之所以有缓存设计是因为这些是我们经常用的数据对象,设定合理的缓存,可以大大提高我们代码执行速度(不用再开辟空间而耗时间了)和大大节约内存空间(不用重复new对象)



接着说说equals这个判断两个对象关系的方法吧。这个方法是Object类里面自带的方法,所有类都是Object类的子类,所以,每个类都有从Object那儿继承下来的equals方法。但是,很多时候,继承下来的判断方法并不适合当前类的个性化比较,所以有很多系统类都是对equals方法进行了重写的!所以我们发现使用equals方法得到的结果差人强意的时候,就一定要去看看该类不是重写了equals方法,如果重写了,重写的规则是什么!这个问题就是我要说的!


我们先去看看Object类中的equals方法的比较规则是什么:

技术分享

我们看出没有重写的equals方法是比较的对象的引用地址;接着我么再看看包装类的equals方法:

技术分享

我们看出8中包装类中的equals方法是被重写了的,重写规则是比较对象的值的大小,不再是比较引用地址了;接着我们一并看看String类的equals方法

技术分享

我们看出String类的equals方法也是被重写了的,重写规则也是比较俩个字符串的值是否相同,相同的话,就返回true


本文出自 “11929788” 博客,请务必保留此出处http://11939788.blog.51cto.com/11929788/1952485

以上是关于JavaSE中==和equals使用的主要内容,如果未能解决你的问题,请参考以下文章

Java面试题JavaSE基础之Object公用方法equals和hashCode深浅拷贝

JavaSE——为什么重写equals的同时一定要重写hashCode?

JavaSE——为什么重写equals的同时一定要重写hashCode?

JavaSE包装类基本类型和字符串之间的转换==和equals的区别

leetcode_1292. Maximum Side Length of a Square with Sum Less than or Equal to Threshold_[二维前缀和](代码片段

JavaSE 方法的使用