Java 集合类HashSet

首先我们自定义Person类,只有姓名和年龄两个属性

class Person{
	private String name ;
	private int age ;
	public Person(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}
	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;
	}
	@Override
	public String toString() {
		return "[name=" + name + ", age=" + age + "]";
	}
}

创建HashSet,元素为Person对象

public class SetDemo1 {
	public  static void main(String args[]) {
		Set<Person> mySet = new HashSet<>();
		mySet.add(new Person("唐三",20)) ;
		mySet.add(new Person("唐三",20)) ;
		mySet.add(new Person("小舞",19)) ;
		System.out.println(mySet);
	}
}

运行结果:
在这里插入图片描述
相同的人存进Set里了,这似乎与Set不存储相同元素的特点相悖。
实质上当执行第一个mySet.add(new Person(“唐三”,20))时,Person对象会被自动分配一个hashcode。执行第二个mySet.add(new Person(“唐三”,20))时Person对象会得到一个不同hashcode,这个hashcode到底从哪来我们可以看下源码
在这里插入图片描述
这个map是HashMap,可见Set底层由Map实现,不过这里并没有求hashcode,继续看此put的源码
在这里插入图片描述
这里显示求出键key的hash值,也就是我们所存入对象的hash值。有兴趣的可以继续往下看底层实现。
由于hashcode不同,所以第二个Person对象可以加入Set集合。如果两对象的hashcode相同就会调用euqals()方法。我们修改代码的思路应该是覆写hashCode方法,让有相同姓名年龄的Person的hashcode相同,同名同龄为同一个Person对象是我们人为规定的,所以我们还要覆写Person的equals()方法让它知道这个规定。(在Eclipse里通过alt+shift+s+h可以快速添加hashCode和equals方法)
Person类代码修改为:

class Person{
	private String name ;
	private int age ;
	
	public Person(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}
	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 String toString() {
		return "[name=" + name + ", age=" + age + "]";
	}
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + age;
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		return result;
	}
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Person other = (Person) obj;
		if (age != other.age)
			return false;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		return true;
	}
}

再次运行SetDemo1结果:
在这里插入图片描述
这样就确保了HashSet里自定义对象的唯一性,关键就是覆写自定义对象的hashCode()和equals()。
上述代码中hashCode()和equals()是使用eclipse快速构建的。为什么hashCode()方法要那样写呢?实质上写成

public int hashCode() {
		return age+name.hashCode();
	}

也可以。但是这样有个弊端就是假设HashSet里有一个Person,名字哈希码是30,年龄20,要加入的Person名字哈希码为29,年龄21,这样就造成虽然两Person对象不同,但后者无法存入。为降低hashcode重复的几率,就将年龄与名字的哈希码进行一定规律的变化。
至于为什么prime是31也有讲究

31是一个质数,公约数少。
31大小适中。太大的话经过一系列乘加可能超出int取值范围,太小重复几率就高了。
31是25-1,好算

Java集合类HashSet是一种基于哈希表实现的集合,它继承自AbstractSet类并实现了Set接口。HashSet类提供了高效的查找、插入和删除操作,可以存储不重复的元素。HashSet类的构造方法有四种形式:HashSet()、HashSet(int initialCapacity)、HashSet(int initialCapacity, float loadFactor)和HashSet(Collection<? extends E> c)。 你可以使用以下代码来创建一个HashSet集合: 1. 使用无参构造方法: HashSet<Integer> set = new HashSet<>(); 2. 使用指定初始容量的构造方法: HashSet<Integer> set1 = new HashSet<>(20); 3. 使用指定初始容量和负载因子的构造方法: HashSet<Integer> set2 = new HashSet<Integer>(20, 0.8f); 4. 使用指定集合的构造方法: HashSet<Integer> set3 = new HashSet<>(new ArrayList<Integer>()); 使用HashSet集合时,需要注意元素的唯一性和哈希值的计算,HashSet类内部使用哈希函数来计算元素的哈希值,并根据哈希值来存储和查找元素。当两个元素的哈希值相同时,HashSet会通过equals()方法来判断它们是否相等。在使用HashSet时,建议重写equals()和hashCode()方法,以确保元素的唯一性和正确的哈希值计算。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [Java集合类HashSet](https://blog.csdn.net/friend_X/article/details/113755564)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值