java中equals,hashcode和==的区别

时间:2021-04-12 16:06:26

==

java中的数据类型,可分为两类:

1.基本数据类型,也称原始数据类型

byte,short,char,int,long,float,double,boolean 他们之间的比较,应用双等号(==),比较的是他们的值。

基本数据类型与其他内存==比较,其他类型都会拆箱转换成基本数据类型

2.引用类型(类、接口、数组)

当他们用(==)进行比较的时候,比较的是他们在内存中的存放地址,所以,除非是同一个new出来的对象,他们的比较后的结果为true,否则比较后结果为false。

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

    public static void main(String[] args) {
        int int1 = 12;
        int int2 = 12;
        Integer Integer1 = new Integer(12);
        Integer Integer2 = new Integer(12);
        Integer Integer3 = new Integer(127);

        Integer a1 = 127;
        Integer b1 = 127;

        Integer a = 128;
        Integer b = 128;

        String s1 = "str";
        String s2 = "str";
        String str1 = new String("str");
        String str2 = new String("str");

        System.out.println("int1==int2:" + (int1 == int2));
        System.out.println("int1==Integer1:" + (int1 == Integer1));
        System.out.println("Integer1==Integer2:" + (Integer1 == Integer2));
        System.out.println("Integer3==b1:" + (Integer3 == b1));
        System.out.println("a1==b1:" + (a1 == b1));
        System.out.println("a==b:" + (a == b));

        System.out.println("s1==s2:" + (s1 == s2));
        System.out.println("s1==str1:" + (s1 == str1));
        System.out.println("str1==str2:" + (str1 == str2));
    }

Output:

int1==int2:true
int1==Integer1:true  //Integer1会自动拆箱转换为int,Integer1==int1,也一样是true
Integer1==Integer2:false //不同对象,内存存放地址不同
Integer3==b1:false  //Integer3指向new的对象地址,b1指向缓存中127地址,地址不同,所以为false
a1==b1:true
a==b:false
s1==s2:true
s1==str1:false
str1==str2:false

Integer b1 = 127;java在编译的时候,被翻译成-> Integer b1 = Integer.valueOf(127);

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

IntegerCache:

private static class IntegerCache {
        static final int low = -128;
        static final int high;
        static final Integer cache[];

        static {
            // high value may be configured by property
            int h = 127;
            String integerCacheHighPropValue =
                sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
            if (integerCacheHighPropValue != null) {
                try {
                    int i = parseInt(integerCacheHighPropValue);
                    i = Math.max(i, 127);
                    // Maximum array size is Integer.MAX_VALUE
                    h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
                } catch( NumberFormatException nfe) {
                    // If the property cannot be parsed into an int, ignore it.
                }
            }
            high = h;

            cache = new Integer[(high - low) + 1];
            int j = low;
            for(int k = 0; k < cache.length; k++)
                cache[k] = new Integer(j++);

            // range [-128, 127] must be interned (JLS7 5.1.7)
            assert IntegerCache.high >= 127;
        }

        private IntegerCache() {}
    }

我们看到IntegerCache的low定义为-128,high默认定义为127.但是high是可以配置的,如果没有配置才是127.我们不去看配置的情况,因为java默认是没有配置的。看一下cache数组,长度为high-low+1,从-128开始到127,存在cache数组内。

从上面的代码中可以看出,java在申请一个大于-128小于127的数时,其实是从cache中直接取出来用的,如果不在这个范围则是new了一个Integer对象。

对于==,他比较的是地址。对于int来说比较的是值。

对于equals,比较的是内容(要看equals的具体实现)。看一下Integer里面的实现:

  public boolean equals(Object obj) {
        if (obj instanceof Integer) {
            return value == ((Integer)obj).intValue();
        }
        return false;
    }

只要都是Integer类型,equals比较的也是值

Byte,Short,Long 的缓存池范围默认都是: -128 到 127。可以看出,Byte的所有值都在缓存区中,用它生成的相同值对象都是相等的。

equals

默认情况(没有覆盖equals方法)下equals方法都是调用Object类的equals方法,而Object的equals方法主要用于判断对象的内存地址引用是不是同一个地址(是不是同一个对象)。

下面是Object类中equals方法:

public boolean equals(Object obj) {
    return (this == obj);
}

定义的equals与==是等效的

要是类中覆盖了equals方法,那么就要根据具体的代码来确定equals方法的作用了,覆盖后一般都是通过对象的内容是否相等来判断对象是否相等。

hasCode

hashCode()方法返回的就是一个数值,从方法的名称上就可以看出,其目的是生成一个hash码。

equals与hasCode关联

  • 如果两个对象equals,Java运行时环境会认为他们的hashcode一定相等。
  • 如果两个对象不equals,他们的hashcode有可能相等。
  • 如果两个对象hashcode相等,他们不一定equals。
  • 如果两个对象hashcode不相等,他们一定不equals。

为什么覆盖equals时总要覆盖hashCode

在每个覆盖了equals方法的类中,也必须覆盖hashCode方法。如果不这样做的话,就会违反Object.hashCode的通用约定,从而导致该类无法结合所有基于散列的集合一起正常运作,这样的集合包括HashMap、HashSet和Hashtable。

因为如果不覆盖equals方法的话,相等的对象可能返回的不相同的hash code。

比如上面这种情况就会出现在hashmap中,

一个对象修改equals,判断里面的字段是否一致即相等,但是没有修改hasCode

hashmap中的key根据hashCode分配到不同的元素,但是用equals尝试,key却是相等的,那就恶心了,会出现很多异常bug.

参考:

java中equals,hashcode和==的区别

JAVA 拾遺--eqauls 和 hashCode 方法

覆盖equals时总要覆盖hashCode