equals
方法在非空对象引用上实现相等关系:
- 自反性:对于任何非空引用值
x
,x.equals(x)
都应返回true
。 - 对称性:对于任何非空引用值
x
和y
,当且仅当y.equals(x)
返回true
时,x.equals(y)
才应返回true
。 - 传递性:对于任何非空引用值
x
、y
和z
,如果x.equals(y)
返回true
,并且y.equals(z)
返回true
,那么x.equals(z)
应返回true
。 - 一致性:对于任何非空引用值
x
和y
,多次调用 x.equals(y) 始终返回true
或始终返回false
,前提是对象上equals
比较中所用的信息没有被修改。 - 对于任何非空引用值
x
,x.equals(null)
都应返回false
。
Object
类的 equals 方法实现对象上差别可能性最大的相等关系;即,对于任何非空引用值 x
和 y
,当且仅当 x
和 y
引用同一个对象时,此方法才返回 true
(x == y
具有值 true
)。
注意:当此方法被重写时,通常有必要重写 hashCode 方法,以维护 hashCode 方法的常规协定,该协定声明相等对象必须具有相等的哈希码。
hashCode
的常规协定是:
- 在 Java 应用程序执行期间,在对同一对象多次调用 hashCode 方法时,必须一致地返回相同的整数,前提是将对象进行 equals 比较时所用的信息没有被修改。从某一应用程序的一次执行到同一应用程序的另一次执行,该整数无需保持一致。
- 如果根据 equals(Object) 方法,两个对象是相等的,那么对这两个对象中的每个对象调用
hashCode
方法都必须生成相同的整数结果。 - 如果根据
equals(java.lang.Object)
方法,两个对象不相等,那么对这两个对象中的任一对象上调用 hashCode 方法不 要求一定生成不同的整数结果。但是,程序员应该意识到,为不相等的对象生成不同整数结果可以提高哈希表的性能。
实际上,由 Object 类定义的 hashCode 方法确实会针对不同的对象返回不同的整数。(这一般是通过将该对象的内部地址转换成一个整数来实现的,但是 JavaTM 编程语言不需要这种实现技巧。)
注:
1、当使用HashSet时,hashCode()方法就会得到调用,判断存储在集合中的对象是hash code值是否与增加的对象的hash code 值一致。
如果不一致,直接加进去;
如果一致,再进行equals方法比较,equals方法如果返回true,表示对象已经加进去了,就不会再增加新的对象,否则加进去
2、如果我们重写equals方法,那么也要重写hashCode方法,反之亦然。
HashSet存放普通的字符串
package com.bjsxt.str;
import java.util.HashSet;
public class SetTest1 {
public static void main(String[] args) {
HashSet set = new HashSet();
System.out.println(set.add("a"));
set.add("b");
set.add("c");
set.add("d");
set.add("a");
System.out.println(set);
}
}
/**
* 运行结果: true [d, b, c, a]
*/
HashSet存放没有重写hashcode和equals方法的对象
package com.bjsxt.str;
import java.util.HashSet;
import org.junit.Test;
public class SetTest2 {
@Test
public void test1() {
HashSet set = new HashSet();
set.add(new People("zhangsan"));
set.add(new People("lisi"));
set.add(new People("zhangsan"));
System.out.println(set);/* 结果:三个对象 */
}
@Test
public void test2() {
HashSet set = new HashSet();
People p1 = new People("zhangsan");
set.add(p1);
set.add(p1);
System.out.println(set);/* 结果:[com.bjsxt.str.People@211b37] */
}
@Test
public void test3() {
HashSet set = new HashSet();
String s1 = new String("a");
String s2 = new String("a");
set.add(s1);
set.add(s2);
System.out.println(set);/* 结果:[a] */
System.out.println(s1.hashCode() == s2.hashCode());// true
}
}
class People {
String name;
public People(String name) {
this.name = name;
}
}
HashSet存放重写hashcode和equals方法的对象
package com.bjsxt.str;
import java.util.HashSet;
import org.junit.Test;
public class SetTest3 {
@Test
public void test1() {
HashSet set = new HashSet();
Student s1 = new Student("zhangsan");
Student s2 = new Student("zhangsan");
set.add(s1);
set.add(s2);
// 开发中一个认为内容相同的就是同一个对象,不考虑地址
System.out.println(set);/* 结果:[com.bjsxt.str.Student@aa9c3074] 认为是一个对象 */
System.out.println(s1.hashCode() == s2.hashCode());// true
}
}
/** Eclipse可以自动生成equals和hashcode方法 */
class Student {
String name;
public Student(String name) {
this.name = name;
}
@Override
public int hashCode() {
// 返回name的hashcode来表示当前类的hashcode
return this.name.hashCode();
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
// 如果obj不为null,且obj是当前类的实例
if (null != obj && obj instanceof Student) {
Student s = (Student) obj;
if (name.equals(s.name)) {
return true;
}
}
return false;
}
}