equals(),==,hashCode()

本来是要梳理在hash集合中,是如何利用equals()和hashCode()判定元素是否重复,但是要说equals()就要谈==,索性一起总结。

参考博文:https://www.cnblogs.com/skywang12345/p/3324958.html

强烈推荐一看。

equals()和==

当是普通数据类型(int,double,char等),==是直接比较值,如果是引用类型数据(String,对象),==是地址比较。

查看超类Object中的源码:

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

可见Object中的equals()和==没有区别。

看equals()在String和AbstractSet中的源码:

二者都覆写了equals()方法,在进行==比较的基础上,还有其他比较。

以String为例,如果两个字符串==返回true,equals()必定返回true;如果==返回false,那么会对字符串中的字符逐一比较,如果字符都相同,equals返回true。

equals()和hashCode()

equals()和hashCode()之间并没有关系,但在hash table算法的集合(hashSet,hashMap等)中,只有当equals()返回为ture,并且两个对象的hashCode()相同,HashSet才会判定为重复元素。

看一下在Set中,关于两个不可重复(duplicate)元素的描述:

/**
 * A collection that contains no duplicate elements.  More formally, sets
 * contain no pair of elements <code>e1</code> and <code>e2</code> such that
 * <code>e1.equals(e2)</code>, and at most one null element.  As implied by
 * its name, this interface models the mathematical <i>set</i> abstraction.
 //...
**/

set不可以有两个元素e1.equals(e2),如果e1,e2属性都相同,在开发者看来,e1和e2是相同的对象,但是在自定义类中不重写equals()方法的话,那么equals()只进行地址比较(使用的是Object中的equals()方法),就会判定e1和e2是两个不同对象,这显然不符合开发者的需求,所以在自定义类中需要重写equals()方法,将对象内容逐一比较。

但equals()的结果为true,不一定说e1和e2就是两个不同元素了。还要看hashCode。

看下面的代码示例:

public class Test {
	public static void main(String[] args) {
		HashSet<Person> hs = new HashSet<Person>();

		Person e1 = new Person("龙根子", 13);
		Person e2 = new Person("龙根子", 13);
		Person e3 = new Person("罗大吊", 17);

		hs.add(e1);
		hs.add(e2);
		hs.add(e3);

		System.out.println("e1和e2是否相同:" + e1.equals(e2));
		System.out.println("e1_hashCode:" + e1.hashCode());
		System.out.println("e2_hashCode:" + e2.hashCode());

		Iterator<Person> iterator = hs.iterator();
		while (iterator.hasNext()) {
			System.out.println(iterator.next());
		}
	}
}

class Person {
	public Person(String name, int age) {
		this.name = name;
		this.age = age;
	}

	public String name;
	public int age;

	// 重写equals()方法,将对象属性逐一比较,如果都相同,返回true
	@Override
	public boolean equals(Object obj) {
		super.equals(obj);
		Person per = (Person) obj;
		if (this.name == per.name && this.age == per.age) {
			return true;
		} else {
			return false;
		}
	}

	@Override
	public String toString() {
		return this.name + "--" + this.age;
	}

}

输出内容:

e1和e2是否相同:true
e1_hashCode:118352462
e2_hashCode:1550089733
龙根子--13
罗大吊--17
龙根子--13

可以看到,即使equals()为true,还是存入了重复的对象。

这是因为二者的hashCode不同,所以HashSet在添加e1和e2的时候,还是认为二者不同。

再重写hashCode()方法:

public class Test {
	public static void main(String[] args) {
		HashSet<Person> hs = new HashSet<Person>();

		Person e1 = new Person("龙根子", 13);
		Person e2 = new Person("龙根子", 13);
		Person e3 = new Person("罗大吊", 17);

		hs.add(e1);
		hs.add(e2);
		hs.add(e3);

		System.out.println("e1和e2是否相同:" + e1.equals(e2));
		System.out.println("e1_hashCode:" + e1.hashCode());
		System.out.println("e2_hashCode:" + e2.hashCode());

		Iterator<Person> iterator = hs.iterator();
		while (iterator.hasNext()) {
			System.out.println(iterator.next());
		}
	}
}

class Person {
	public Person(String name, int age) {
		this.name = name;
		this.age = age;
	}

	public String name;
	public int age;

	// 重写equals()方法,将对象属性逐一比较,如果都相同,返回true
	@Override
	public boolean equals(Object obj) {
		super.equals(obj);
		Person per = (Person) obj;
		if (this.name == per.name && this.age == per.age) {
			return true;
		} else {
			return false;
		}
	}
	
	//重写hashCode()
	@Override
	public int hashCode() {
                //二者的name,age如果相同的话
		//返回nameHash^age的值也一定相同
		int nameHash = name.toUpperCase().hashCode();
		return nameHash ^ age;
	}

	@Override
	public String toString() {
		return this.name + "--" + this.age;
	}
}

输出结果:

e1和e2是否相同:true
e1_hashCode:40114077
e2_hashCode:40114077
罗大吊--17
龙根子--13

可以看到e1.equals()为true,e1和e2的hashCode相同,所以HashSet判定二者为重复(duplicate)元素,所以不会重复存入。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值