美文网首页
【JAVA】== 和 equals

【JAVA】== 和 equals

作者: 温柔的谢世杰 | 来源:发表于2019-07-27 12:02 被阅读0次

    一、integer的==

    public class Test03 {
     
         
        public static void main(String[] args) {
            
            Integer f1 = 100, f2 = 100, f3 = 150, f4 = 150;
     
              
            System. out.println( f1 == f2); //true
            System. out.println( f3 == f4); //false
        }
    }
    

    当我们给一个 Integer 赋予一个 int 类型的时候会调用 Integer 的静态方法 valueOf。
    Integer f1 = Integer.valueOf(100);
    Integer f2 = Integer.valueOf(100);
    Integer f3 = Integer.valueOf(150);
    Integer f4 = Integer.valueOf(150);
    思考:那么 Integer.valueOf()返回的 Integer 是不是是重新 new Integer (num); 来创建的呢?如果是这样的话,那么 == 比较返回都是 false,因为他们引用的堆地址不一样。

    具体来看看 Integer.valueOf 的源码

    public static Integer valueOf(int i) {
             //范围-128到127
            if (i >= IntegerCache.low && i <= IntegerCache.high)
                return IntegerCache.cache[i + (-IntegerCache.low)];
            return new Integer(i);
    }
    

    从上面我们可以知道给 Interger 赋予的 int 数值在 - 128 - 127 的时候,直接从 cache 中获取,这些 cache 引用对 Integer 对象地址是不变的,但是不在这个范围内的数字,则 new Integer (i) 这个地址是新的地址,不可能一样的.


    二、string的==

    1. String str=new String ("abc") 和 String str="abc" 的字符串 “abc” 都是存放在堆中,而不是存在栈中。

    2. 其实在在 java 中有一个 “字符数据池” 的内存管理机制。

    3. String str="abc",执行这句话时,会先去 “字符数据池” 搜索时候有 “abc” 这个字符串,如果有,则将字符串的首地址赋值给 str,如果没有,生成一个新的字符串 “abc” 并且将首地址赋值给 str;

    4. String str=new String ("abc"),执行这句话时,不会考虑时候已经存在了 “abc” 这个字符串,而是直接生成一个新的字符串 “abc” 并将首地址赋值给 str,如果池中没有字符串,则把这个"abc"放入字符串池中(此时是创建了两个对象,一个堆中,一个池中);

    5. 由以上分析可知,String str="abc" 和效率要高于 String str=new String ("abc"),因为如果有重复的字符串时,第一种方式可以节省空间。

    6. 下面举例说明一下,好好看看结果,仔细分析原因,上面已经说明的很清楚了:

    public class Test{
     public static void main(String args[]){
      String s1=new String ("abc");// 直接在堆中生成新的 “abc”
      String s2=new String ("abc");// 直接在堆中生成新的 “abc”
      String s3="abc";// 先去 “字符数据池” 搜索时候有 “abc” 这个字符串,如果有,则将字符串的首地址赋值给 s3,如果没有,则在 “字符数据池” 中生成一个新的字符串 “abc” 并且将首地址赋值给 s3;  
      String s4="abc";// 去 “字符数据池” 搜索时发现了上一步生成的 “abc” 这个字符串,把该字符串首地址赋值给 s4,这时其实 s3 和 s4 指向同一个字符数据池中的 “abc”
      System.out.println(s1==s2);
      System.out.println(s1==s3);
      System.out.println(s2==s3);
      System.out.println(s3==s4);
     }
    }
    

    结果:
    false
    fasle
    false
    true


    三、基本类型和包装类的==和equals(涉及拆装箱)

    1、基本型和基本型的封装型进行 "= =" 运算符的比较,基本型的封装型将会自动拆箱变为基本型后再进行比较,因此 Integer (0) 会自动拆箱为 int 类型再进行比较,显然返回 true;

    2、两个 Integer 类型进行 "= =" 比较,如果其值在 - 128 至 127,那么返回 true,否则返回 false, 这跟 Integer.valueOf () 的缓冲对象有关,这里不进行赘述。

    3、两个基本型的封装型进行 equals () 比较,首先 equals () 会比较类型,如果类型相同,则继续比较值,如果值也相同,返回 true

    4、基本型封装类型调用 equals (), 但是参数是基本类型,这时候,先会进行自动装箱,基本型转换为其封装类型,再进行 3 中的比较。

    5、对于equal方法来说,如果没有重写过,那么就是相当于==,equals方法是基类Object的方法,所有对象都可以调用这个方法,而equals底层实现就是==,也就是直接比较地址的,所以呢,如果没有重写equal方法的对象调用equal方法,是直接比较对象地址的。


    四、关于equal和 == 的总结

    1. '==' 是用来比较两个变量(基本类型和对象类型)的值是否相等的, 如果两个变量是基本类型的,那很容易,直接比较值就可以了。如果两个变量是对象类型的,那么它还是比较值,只是它比较的是这两个对象在栈中的引用(即地址)

    2. 对象是放在堆中的,栈中存放的是对象的引用(地址),由此可见 '==' 是对栈中的值进行比较的。如果要比较堆中对象的内容是否相同,那么就要重写 equals 方法了。

    3. Object 类中的 equals 方法就是用 '==' 来比较的,所以如果没有重写 equals 方法(string是重写了equal方法的),equals 和 == 是等价的。 通常我们会重写 equals 方法,让 equals 比较两个对象的内容,而不是比较对象的引用(地址)因为往往我们觉得比较对象的内容是否相同比比较对象的引用(地址)更有意义。

    4. Object 类中的 hashCode 是返回对象在内存中地址转换成的一个 int 值(可以就当做地址看)。所以如果没有重写 hashCode 方法,任何对象的 hashCode 都是不相等的。通常在集合类的时候需要重写 hashCode 方法和 equals 方法,因为如果需要给集合类(比如:HashSet)添加对象,那么在添加之前需要查看给集合里是否已经有了该对象,比较好的方式就是用 hashCode。

    5. 注意的是 String、Integer、Boolean、Double 等这些类都重写了 equals 和 hashCode 方法,这两个方法是根据对象的内容来比较和计算 hashCode 的。(详细可以查看 jdk 下的 String.java 源代码),所以只要对象的基本类型值相同,那么 hashcode 就一定相同。

    相关文章

      网友评论

          本文标题:【JAVA】== 和 equals

          本文链接:https://www.haomeiwen.com/subject/thwsrctx.html