HashSet是如何去重的

首先来介绍一下HashSet的主要特征

  1. 实现了Collection接口的子类:Set接口。
  2. HashSet的储存是无序的,即遍历的顺序和我们添加的顺序无关。
  3. HashSet底层的数据结构是哈希表。根据哈希表得出的哈希值代表该对象的储存位置
  4. HashSet不能添加重复的元素,是基于HashMap实现的

HashSet如何去重

由上面的第四点我们可以看到,HashSet是不能添加重复元素的,那么他是如何实现的呢?
一般来说,一个类必要时会同时重写hashCode()和equals()两个方法(如果没有重写,那么就默认调用Object中的hashCode()和equals())。这也是HashSet去重机制的关键。

  1. 首先是重写的hashCode()。如果在该方法中,两个对象通过重写后计算出来的哈希码是不同的,那么就直接判定这两个对象不是同一个对象,即可以同时存放进HashSet集合。
  2. 当两个对象通过重写后计算出来的哈希码是相同的,那么调用重写后的equals方法。如果返回false,说明这两个对象不同,即可以同时存放进HashSet集合,反之则不可以。

代码示例
自定义User类


public class User {
	
	private String name;
	private String sex;
	private int age;
	
	public User(String name,String sex,int age) {
		this.name=name;
		this.sex=sex;
		this.age=age;
		
	}
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getSex() {
		return sex;
	}
	public void setSex(String sex) {
		this.sex = sex;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	
	/**
	 * 重写toString
	 */
	public String toString() {
		return name+"--"+sex+"--"+"--"+age;
	}

}

当没有重写hashCode()和equals()

public class test {

	public static void main(String[] args) {
		
		User user1 = new User("张三","男",20);
		User user2 = new User("张三","男",20);
		Set<User> users = new HashSet<User>();
		users.add(user1);
		users.add(user2);
		
		//遍历
		Iterator<User> iterator = users.iterator();
		while(iterator.hasNext()) {
			System.out.println(iterator.next());
		}
		
	}
}

运行结果

张三--男----20
张三--男----20

可以发现,这里user1和uer2都被添加进HashSet集合中。因为我这里没有重写hashCode()和equals(),所以这里默认使用了Object类中的hashCode(),通过Object中hashCode()得出的user1和user2的哈希值是不同的,因为他们的存放地址是不一样。即直接判定这两个对象是不同的,可以同时放入HashSet集合。

但是如果改变判定规则,两个对象即使存储位置不同,只要属性完全相同就不能存放进HashSet。这个时候就需要重写hashCode()和equals()方法。

在User类中添加重写的hashCode()和equals()方法。

public int hashCode() {
		
		int result = 17;
		result = result*31 + this.name.hashCode();
		result = result*31 + this.sex.hashCode();
		result = result*31 + this.age;
		return result;
		
	}
	
	/**
	 * 重写equals
	 */
	public boolean equals(Object obj) {
		
		if(this == obj){
            return true;//地址相等
        }

        if(obj == null){
            return false;//非空性:对于任意非空引用x,x.equals(null)应该返回false。
        }
        if(obj instanceof User) {
        	User user  = (User)obj;
        	if(this.name.equals(user.name)&&this.sex.equals(user.sex)&&this.age==user.age) {
        		return true;
        	}
        }
		return false;
	}

运行结果

张三--男----20

可以发现,这个时候只能加入一个user,并且是user1。(因为user1先执行add操作)通过重写了hashCode()和equals()方法,我们修改了判定规则,我们通过属性的hash值返回hashCode的结果,并且在重写后的equals()方法通过比较属性来判断是否是同一个对象。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值