Java Set接口contains(Object o)方法与对象hashCode()方法的关系梳理

概述

接下来我们要讨论如下问题:
1、Set接口的contains方法,判断是否包含的依据是什么?
2、对象hashCodeequals方法之间的关系

1、Set接口的contains方法,判断是否包含的依据是什么?

我查看了一下接口文档,里面是这样描述的:
该方法重写了Collection接口的contains方法

Returns true if this set contains the specified element. More formally, returns true if and only if this set contains an element e such that (o == null ? e==null : o.equals(e)).

也就是说,当且仅当
1:参数o,如果o为空,set中也有空时
2:参数o.equals(e),e为set中的一个元素
上述两种情况,会返回true。

2、对象hashCodeequals方法之间的关系

同样,阅读接口文档,equals方法说明如下:

Note that it is generally necessary to override the hashCode method whenever this method is overridden, so as to maintain the general contract for the hashCode method, which states that equal objects must have equal hash codes

就是说,如果一个对象重写了equals方法,通常也需要重写hashCode方法。根据契约约定,如果两个对象相等,则它们的hash值必须相等。
换句话说,如果两个对象的hash值不同,则调用它们的.equals去比较,肯定返回false

阅读hashCode的文档说明:

If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.

如果两个对象相等,则必须返回相等的hash值。这和equals说明一致。

It is not required that if two objects are unequal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce distinct integer results. However, the programmer should be aware that producing distinct integer results for unequal objects may improve the performance of hash tables.

简单的说,如果两个对象不相等,它们的hash值可能相等。
所以,不能认为hash值一样,就说两个对象相等。

As much as is reasonably practical, the hashCode method defined by class Object does return distinct integers for distinct objects. (This is typically implemented by converting the internal address of the object into an integer, but this implementation technique is not required by the JavaTM programming language.)

通常,不同对象还是需要返回不同的hash值。通常是通过将对象的内部地址转换为integer实现的。

代码验证

我自定义一个Dog对象,先不重写equalshashCode,当Set中添加了两个白色的狗对象时,我们用contains方法去校验Set中是否包含白色的狗对象,会得到如下结果:

import java.util.HashSet;
import java.util.Set;

/**
 * created at 2018-10-08 17:24
 * @author lerry
 */

class Dog {
	String color;

	public Dog(String s) {
		color = s;
	}
}

public class SetAndHashCode {

	public static void main(String[] args) {
		Set<Dog> dogSet = new HashSet<>();
		dogSet.add(new Dog("white"));
		dogSet.add(new Dog("white"));

		System.out.printf("we have %d white dogs", dogSet.size());
		System.out.println();

		if (dogSet.contains(new Dog("white"))) {
			System.out.println("Set has white dog!");
		}
		else {
			System.out.println("Set don't have white dog!");
		}

	}
}
/*
console results:
we have 2 white dogs
Set don't have white dog!
 */

这说明:
默认new一个新对象,会产生新的hash值。

可以验证一下:

public class SetAndHashCode {
	public static void main(String[] args) {
		System.out.println(new Dog("white").hashCode());
		System.out.println(new Dog("white").hashCode());
	}
}
/*
console results:
2000502626
704603837
 */

接下来,我们重新Dog类的equals方法,让类认为只要颜色一样,就算相等:

class Dog {
	String color;

	public Dog(String s) {
		color = s;
	}

	public String getColor() {
		return color;
	}

	@Override
	public boolean equals(Object obj) {
		if (obj instanceof Dog && this.color.equals(((Dog) obj).getColor())) {
			return true;
		}
		else {
			return false;
		}
	}
}

public class SetAndHashCode {

	public static void main(String[] args) {
		Set<Dog> dogSet = new HashSet<>();
		dogSet.add(new Dog("white"));
		dogSet.add(new Dog("white"));

		System.out.printf("we have %d white dogs", dogSet.size());
		System.out.println();

		if (dogSet.contains(new Dog("white"))) {
			System.out.println("Set has white dog!");
		}
		else {
			System.out.println("Set don't have white dog!");
		}

	}
}
/*
console results:
we have 2 white dogs
Set don't have white dog!
 */

但是结果并没有什么改变。对了,根据如果两个对象相等,则它们的hash值必须相等原则,我们还应该去重写hashCode方法:

@Override
	public int hashCode() {
		return this.color.hashCode();
	}

这时,控制台返回的结果终于变成了:

we have 1 white dogs
Set has white dog!

Set对重复元素,进行了去重。所以,添加了两次

		dogSet.add(new Dog("white"));
		dogSet.add(new Dog("white"));

后,dogSet.size()依旧为1

参考

Java中hashCode与equals方法的约定及重写原则
jdk api

代码环境描述

jdk 1.7
macOS 10.13.4

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值