关于java:java中equalshashcode和的区别

19次阅读

共计 5793 个字符,预计需要花费 15 分钟才能阅读完成。

1、==

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));  
  
    } /./* 欢送退出 java 交换 Q 君样:909038429 一起吹水聊天 

输入后果:

int1==int2:true
int1==Integer1:true //Integer 会主动拆箱为 int,所以为 true
Integer1==Integer2:false// 不同对象,在内存寄存地址不同,所以为 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) {  
        assert IntegerCache.high >= 127;  
        if (i >= IntegerCache.low && i <= IntegerCache.high)  
            return IntegerCache.cache[i + (-IntegerCache.low)];  
        return new Integer(i);  
    }  

看一下源码大家都会明确,对于 -128 到 127 之间的数,会进行缓存,Integer b1 = 127 时,会将 127 进行缓存,下次再写 Integer i6 = 127 时,就会间接从缓存中取,就不会 new 了。所以 a1==b1:true a==b:false

2、equals

1、默认状况(没有笼罩 equals 办法)下 equals 办法都是调用 Object 类的 equals 办法,而 Object 的 equals 办法次要用于判断对象的内存地址援用是不是同一个地址(是不是同一个对象)。上面是 Object 类中 equals 办法:

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

定义的 equals 与 == 是等效的

2、要是类中笼罩了 equals 办法,那么就要依据具体的代码来确定 equals 办法的作用了,笼罩后个别都是通过对象的内容是否相等来判断对象是否相等。上面是 String 类对 equals 进行了重写:

public boolean equals(Object anObject) {if (this == anObject) {return true;}  
    if (anObject instanceof String) {String anotherString = (String)anObject;  
        int n = count;  
        if (n == anotherString.count) {char v1[] = value;  
        char v2[] = anotherString.value;  
        int i = offset;  
        int j = anotherString.offset;  
        while (n-- != 0) {if (v1[i++] != v2[j++])  
            return false;  
        }  
        return true;  
        }  
    }  /./* 欢送退出 java 交换 Q 君样:909038429 一起吹水聊天
    return false;  
    }  

即 String 中 equals 办法判断相等的步骤是:

1. 若 A ==B 即是同一个 String 对象 返回 true

2. 若比照对象是 String 类型则持续,否则返回 false

3. 判断 A、B 长度是否一样,不一样的话返回 false

4。一一字符比拟,若有不相等字符,返回 false

这里对 equals 从新须要留神五点:
1 自反性:对任意援用值 X,x.equals(x) 的返回值肯定为 true.
2 对称性:对于任何援用值 x,y, 当且仅当 y.equals(x) 返回值为 true 时,x.equals(y) 的返回值肯定为 true;
3 传递性:如果 x.equals(y)=true, y.equals(z)=true, 则 x.equals(z)=true
4 一致性:如果参加比拟的对象没任何扭转,则对象比拟的后果也不应该有任何扭转
5 非空性:任何非空的援用值 X,x.equals(null) 的返回值肯定为 false

实现高质量 equals 办法的窍门:
1. 应用 == 符号查看“参数是否为这个对象的援用”。如果是,则返回 true。这只不过是一种性能优化,如果比拟操作有可能很低廉,就值得这么做。
2. 应用 instanceof 操作符查看“参数是否为正确的类型”。如果不是,则返回 false。一般来说,所谓“正确的类型”是指 equals 办法所在的那个类。
3. 把参数转换成正确的类型。因为转换之前进行过 instanceof 测试,所以确保会胜利。
4. 对于该类中的每个“要害”域,查看参数中的域是否与该对象中对应的域相匹配。如果这些测试全副胜利,则返回 true; 否则返回 false。
5. 当编写实现了 equals 办法之后,查看“对称性”、“传递性”、“一致性”。

3、hashCode

hashCode() 办法返回的就是一个数值,从办法的名称上就能够看出,其目标是生成一个 hash 码。hash 码的主要用途就是在对对象进行散列的时候作为 key 输出,据此很容易推断出,咱们须要每个对象的 hash 码尽可能不同,这样能力保障散列的存取性能。事实上,Object 类提供的默认实现的确保障每个对象的 hash 码不同(在对象的内存地址根底上通过特定算法返回一个 hash 码)。Java 采纳了哈希表的原理。哈希(Hash)实际上是集体名,因为他提出一哈希算法的概念,所以就以他的名字命名了。哈希算法也称为散列算法,是将数据依特定算法间接指定到一个地址上。初学者能够这样了解,hashCode 办法实际上返回的就是对象存储的物理地址(理论可能并不是)。

散列函数, 散列算法, 哈希函数。
是一种从任何一种数据中创立小的数字“指纹”的办法。
散列函数将任意长度的二进制值映射为较短的固定长度的二进制值,这个小的二进制值称为哈希值。
好的散列函数在输出域中很少呈现散列抵触。

所有散列函数都有如下一个根本个性:
1:如果 a =b,则 h(a) = h(b)。
2:如果 a!=b,则 h(a) 与 h(b) 可能失去雷同的散列值。

Object 的 hashCode 办法:返回一个 int 类型

public native int hashCode();  

3.1 hashCode 的作用

想要明确,必须要先晓得 Java 中的汇合。
总的来说,Java 中的汇合(Collection)有两类,一类是 List,再有一类是 Set。前者汇合内的元素是有序的,元素能够反复;后者元素无序,但元素不可反复。

那么这里就有一个比较严重的问题了:要想保障元素不反复,可两个元素是否反复应该根据什么来判断呢?

这就是 Object.equals 办法了。然而,如果每减少一个元素就查看一次,那么当元素很多时,后增加到汇合中的元素比拟的次数就十分多了。也就是说,如果汇合中当初曾经有 1000 个元素,那么第 1001 个元素退出汇合时,它就要调用 1000 次 equals 办法。这显然会大大降低效率。
于是,Java 采纳了哈希表的原理。

这样一来,当汇合要增加新的元素时,

先调用这个元素的 hashCode 办法,就一下子能定位到它应该搁置的物理地位上。

如果这个地位上没有元素,它就能够间接存储在这个地位上,不必再进行任何比拟了;

如果这个地位上曾经有元素了,就调用它的 equals 办法与新元素进行比拟,雷同的话就不存,不雷同就散列其它的地址。所以这里存在一个抵触解决的问题。这样一来理论调用 equals 办法的次数就大大降低了,简直只须要一两次。

4、eqauls 办法和 hashCode 办法关系

Java 对于 eqauls 办法和 hashCode 办法是这样规定的:

(1) 同一对象上屡次调用 hashCode() 办法,总是返回雷同的整型值。

(2) 如果 a.equals(b),则肯定有 a.hashCode() 肯定等于 b.hashCode()。

(3) 如果!a.equals(b),则 a.hashCode() 不肯定等于 b.hashCode()。此时如果 a.hashCode() 总是不等于 b.hashCode(),会进步 hashtables 的性能。

(4)a.hashCode()==b.hashCode() 则 a.equals(b) 可真可假

(5)a.hashCode()!= b.hashCode() 则 a.equals(b) 为假。

下面论断简记:

1、如果两个对象 equals,Java 运行时环境会认为他们的 hashcode 肯定相等。
2、如果两个对象不 equals,他们的 hashcode 有可能相等。
3、如果两个对象 hashcode 相等,他们不肯定 equals。
4、如果两个对象 hashcode 不相等,他们肯定不 equals。

对于这两个办法的重要标准:

标准 1:若重写 equals(Object obj) 办法,有必要重写 hashcode() 办法,确保通过 equals(Object obj) 办法判断后果为 true 的两个对象具备相等的 hashcode() 返回值。说得简略点就是:“如果两个对象雷同,那么他们的 hashcode 应该相等”。不过请留神:这个只是标准,如果你非要写一个类让 equals(Object obj) 返回 true 而 hashcode() 返回两个不相等的值,编译和运行都是不会报错的。不过这样违反了 Java 标准,程序也就埋下了 BUG。

标准 2:如果 equals(Object obj) 返回 false,即两个对象“不雷同”,并不要求对这两个对象调用 hashcode() 办法失去两个不雷同的数。说的简略点就是:“如果两个对象不雷同,他们的 hashcode 可能雷同”。

5、为什么笼罩 equals 时总要笼罩 hashCode
一个很常见的谬误本源在于没有笼罩 hashCode 办法。在每个笼罩了 equals 办法的类中,也必须笼罩 hashCode 办法。如果不这样做的话,就会违反 Object.hashCode 的通用约定,从而导致该类无奈联合所有基于散列的汇合一起失常运作,这样的汇合包含 HashMap、HashSet 和 Hashtable。

1. 在应用程序的执行期间,只有对象的 equals 办法的比拟操作所用到的信息没有被批改,那么对这同一个对象调用屡次,hashCode 办法都必须始终如一地返回同一个整数。在同一个应用程序的屡次执行过程中,每次执行所返回的整数能够不统一。

2. 如果两个对象依据 equals() 办法比拟是相等的,那么调用这两个对象中任意一个对象的 hashCode 办法都必须产生同样的整数后果。

3. 如果两个对象依据 equals() 办法比拟是不相等的,那么调用这两个对象中任意一个对象的 hashCode 办法,则不肯定要产生雷同的整数后果。然而程序员应该晓得,给不相等的对象产生截然不同的整数后果,有可能进步散列表的性能。

6、总结:
1、equals 办法用于比拟对象的内容是否相等(笼罩当前)

2、hashcode 办法只有在汇合中用到

3、当笼罩了 equals 办法时,比拟对象是否相等将通过笼罩后的 equals 办法进行比拟(判断对象的内容是否相等)。

4、将对象放入到汇合中时,首先判断要放入对象的 hashcode 值与汇合中的任意一个元素的 hashcode 值是否相等,如果不相等间接将该对象放入汇合中。如果 hashcode 值相等,而后再通过 equals 办法判断要放入对象与汇合中的任意一个对象是否相等,如果 equals 判断不相等,间接将该元素放入到汇合中,否则不放入。

最新 2020 整顿收集的一些高频面试题(都整顿成文档),有很多干货,蕴含 mysql,netty,spring,线程,spring cloud、jvm、源码、算法等具体解说,也有具体的学习规划图,面试题整顿等,须要获取这些内容的敌人请加 Q 君样:909038429
/./* 欢送退出 java 交换 Q 君样:909038429 一起吹水聊天

正文完
 0