天天看点

==、equals 与 hashCode

1、==

在 Java 中,"==" 运算符用来比较两个引用以查看它们是否指向同一个内存对象。(即比较的是两个对象的引用地址)

而对于基本数据类型(java 自带类型),直接比较的是值。例如,int a = 3; int b = 3; a == b,返回的是 true。这里 a 和 b 地址不同,但它们是自带类型,比较的是值,所以返回 true。

String 作为开发过程中常用的类,Java 类库的设计者在实现时做了个小小的变化,即采用了享元模式。

每当生成一个新内容的字符串时,它们都会被添加到 String 的缓冲池中,当第二次再次生成相同内容的字符串实例时,就会共享此对象,而不是去创建一个新的对象,这样的做法仅仅适合于通过 = 符号进行的初始化,如果是通过 new 进行的初始化,则会创建一个新的对象。

扩展:

对 Boolean、Character、Byte、Shot、Integer、Long、Float、Double 来说,和 String 一样,"==" 比较的是引用地址,equals() 比较的是内容,这些已经在 java 自带的封装类里重载好了。

StringBuffer:

StringBuffer a = new StringBuffer("hello");
StringBuffer b = new StringBuffer("hello");
System.out.println(a == b); // false
System.out.println(a.equals(b)); // false
           

因为 StringBuffer 从 Object 里继承了 equals(),所以 equals 仍然比较的是引用地址,a,b 的内存地址不同,所以 a.equals(b) 返回 false。

2、equals

equals 是 Object 类提供的方法之一,因为每一个 Java 类都继承自 Object 类,所以每一个对象都有 equals() 方法。

因为 Object 类中定义的 equals() 方法是直接使用 “==” 运算符比较两个对象,所以在没有覆盖 equals() 方法的情况下,equals() 方法比较的是引用地址。

相比于 “==” 运算符,equals() 方法的特殊之处在于它可以被覆盖,所以可以通过重写 equals() 方法让它不是比较引用地址,而是比较数据内容。

例如,String 类就对 equals() 方法进行了重写,重写后比较的是两个独立对象的内容是否相等,即堆中内容是否相等。

3、hashCode

hashCode() 方法是从 Object 类中继承过来的,它用来鉴定两个对象是否相等。Object 类中的 hashCode() 方法返回对象在内存中地址转换成的一个 int 值,所以如果没有重写 hashCode() 方法,任何对象的 hashCode() 方法都是不相等的。

注意:

一般在重写 equals() 方法的同时也要重写 hashCode() 方法,否则就违反了 Object.hashCode 的通用约定,从而导致该类无法与所有基于散列值(hash)的集合类(HashMap、HashSet、HashTable)结合在一起正常运行。

扩展:

如果 x.equals(y) 返回 true,那么调用两个对象中任意一个对象的 hashCode() 方法都必须产生同样的整数结果。

如果 x.equals(y) 返回 false,那么 x 和 y 的 hashCode() 方法返回值有可能相等,有可能不相等。

反过来,hashCode() 方法返回值不相等,一定能推出 equals() 方法返回 false,而 hashCode() 方法返回值相等,equals() 方法返回值有可能为 true,也可能为 false。

为不相等的对象生成不同整数结果(hashCode 值)可以提高哈希表的性能