HashSet的去重原理

set集合没有索引值,不能重复,底层是map。

当新增元素时,会先调用hashCode()方法,计算对象的哈希值,然后用哈希值%数组长度,算出新增元素的索引值位置;若该索引值位置没有元素,就直接新增,

若该索引值位置有元素,则调用equals()方法,判断两个元素是否重复;若重复,不新增,若不重复,则新增。

具体看代码实现:

//情况一:

这里Set集合的泛型是 String,这是JDK自带的类,按住‘ctrl’键,点击String,查看源码:发现它覆盖重写了Object类的hashCode() 和 equals()方法,所以会自动调用方法进行判断去重。

 测试类:添加几条数据,看看输出结果

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

public class Test01 {
	public static void main(String[] args) {
		Set<String> set = new HashSet<>();
		set.add("张三");
		set.add("李四");
		set.add("王五");
		set.add("张三");
		
		System.out.println(set.size());
		System.out.println(set);
	}

}

输出结果为:

3
[李四, 张三, 王五]

//情况二:

接下来,我们给Set集合自定义泛型,看看啥情况:

自定义一个Student类,提供基本的get,set方法,无参构造和有参构造,toString()方法

然后再新建set集合,添加几个学生对象,打印看看结果 

package HashSet去重原理;

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

public class Test02 {
	public static void main(String[] args) {
		//自定义泛型:Student
		Set<Student> set = new HashSet<>();
		set.add(new Student("张三", 22, 1000));
		set.add(new Student("李四", 33, 2000));
		set.add(new Student("王五", 44, 3000));
		set.add(new Student("张三", 22, 1000));
		
		System.out.println(set.size());
		for (Student stu : set) {
			System.out.println(stu);
		}
	}

}

class Student{
	private String name;
	private int age;
	private int money;
	
	
	@Override
	public String toString() {
		return "Student [name=" + name + ", age=" + age + ", money=" + money + "]";
	}
	public Student() {
		super();
		// TODO Auto-generated constructor stub
	}
	public Student(String name, int age, int money) {
		super();
		this.name = name;
		this.age = age;
		this.money = money;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public int getMoney() {
		return money;
	}
	public void setMoney(int money) {
		this.money = money;
	}
}

控制台输出结果为:

 4
Student [name=王五, age=44, money=3000]
Student [name=张三, age=22, money=1000]
Student [name=李四, age=33, money=2000]
Student [name=张三, age=22, money=1000]

这里自定义的Student类,因为没有重写Object类的hashCode() 和 equals()方法,所以不会进行去重判断

//情况三:

这次我们在 情况二 的基础上,给student类,加上hashCode() 和 equals()方法,并给里面加上一个输出语句,看看结果

( 快捷键:alt+shift+s )

package HashSet去重原理;

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

public class Test02 {
	public static void main(String[] args) {
		//自定义泛型:Student
		Set<Student> set = new HashSet<>();
		set.add(new Student("张三", 22, 1000));
		set.add(new Student("李四", 33, 2000));
		set.add(new Student("王五", 44, 3000));
		set.add(new Student("张三", 22, 1000));
		
		System.out.println(set.size());
		for (Student stu : set) {
			System.out.println(stu);
		}
	}
}

class Student{
	private String name;
	private int age;
	private int money;
	
	@Override
	public int hashCode() {
		System.out.println("执行了 hashCode方法,判断索引值位置 有没有元素"); //
		final int prime = 31;
		int result = 1;
		result = prime * result + age;
		result = prime * result + money;
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		return result;
	}
	@Override
	public boolean equals(Object obj) {
		System.out.println("执行了 equals方法,判断 新旧元素 是否重复"); //
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Student other = (Student) obj;
		if (age != other.age)
			return false;
		if (money != other.money)
			return false;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		return true;
	}
	@Override
	public String toString() {
		return "Student [name=" + name + ", age=" + age + ", money=" + money + "]";
	}
	public Student() {
		super();
		// TODO Auto-generated constructor stub
	}
	public Student(String name, int age, int money) {
		super();
		this.name = name;
		this.age = age;
		this.money = money;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public int getMoney() {
		return money;
	}
	public void setMoney(int money) {
		this.money = money;
	}
}

输出结果为:

 执行了 hashCode方法,判断索引值位置 有没有元素
执行了 hashCode方法,判断索引值位置 有没有元素
执行了 hashCode方法,判断索引值位置 有没有元素
执行了 hashCode方法,判断索引值位置 有没有元素
执行了 equals方法,判断 新旧元素 是否重复
3
Student [name=李四, age=33, money=2000]
Student [name=张三, age=22, money=1000]
Student [name=王五, age=44, money=3000]

我们发现:这里调用了4次hashCode()方法,因为新增了四个元素,所以判断了4次;

 只调用了一次equals()方法,因为新增元素里面,第一个和第四个重复了,所以只调用一次。

总结:Set集合添加元素时:

① 如果泛型是JKD提供的类,只需要提供基本的get,set方法,无参构造,有参构造,toString()方法 ,即可实现去重

② 如果泛型是自定义的类,必须加上 hashCode() 和 equals()方法,才能实现去重


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值