Set集合解析

首先我们来说一下Set的特点:无序,无下标,对象不能重复。

无序或内部排序:我所理解的无序就是集合输出的顺序和添加元素时的顺序不一致即为无序。

对象不能重复:顾名思义就是集合中不能存储属性值相同的对象(对于对象不能重复,String类型的会自动判断,判断属性相同的对象是否存在于集合中需重写equals方法,但我们在用Set集合时,一般不止用于String类型判断,所以知道重写equals方法是至关重要的,那么我接下来会带大家剖析并重写equals方法。)

java set 合并 去重 java set去重原理_属性值


我们可以看到,在给Set集合中添加学生对象时。虽然对象属性值相同。但是重复的对象还是添加进了Set集合中,并且相同属性的对象,内存地址不一致,这是因为在Java中,实例化一个新对象,就会在内存中开辟一个新的内存空间用于存储对象。知道这个关键信息之后,接下来我们再来剖析一下equals方法

java set 合并 去重 java set去重原理_序列化_02


我们可以看到equals方法中的参数为object类型,是一个引用类型,而引用类型比较的根本就是比较对象的存储地址,如果地址不一样,则判断为一个全新的对象,这也就可以解释了,为什么相同属性的对象,内存地址不一致,而且还可以添加至Set,那怎么解决对象重复的问题呢?了解了equals的底层源码后。那我们只要重写equals方法就可以解决这个问题。

重写equals方法,就必须要重写hashcode方法。

首先,找到我们的实体类,右键鼠标–》找到Source并把鼠标放上去–》再点击Generate hashcode() and equals(),选中你所需要处理的对象属性。

点击之后就会看到,你的实体类就会多两个方法,再然后我们我们实现一个接口Serializable,启用Java序列化功能。

大家可以参考一下我的学生实体类。

package com.zking.collection_02;
import java.io.Serializable;
//Serializable序列化:
//	序列化的作用就是为了不同jvm之间共享实例对象的一种解决方案.由java提供此机制,
//		效率之高,是其他解决方案无法比拟的.属于自家的东西。
public class Student implements Serializable {
	private int sid;
	private String sname;
	private String ssex;
	public int getSid() {
		return sid;
	}
	public void setSid(int sid) {
		this.sid = sid;
	}
	public String getSname() {
		return sname;
	}
	public void setSname(String sname) {
		this.sname = sname;
	}
	public String getSsex() {
		return ssex;
	}
	public void setSsex(String ssex) {
		this.ssex = ssex;
	}
	public Student(int sid, String sname, String ssex) {
		super();
		this.sid = sid;
		this.sname = sname;
		this.ssex = ssex;
	}
	public Student() {
		super();
	}

	/**
	 * 作用于比较各属性值是否相等
	 * 如果各值都相等就执行本页面equals方法
	 * 如果一个或多个值不相同时,直接判断为一个新对象,允许添加,不执行equals方法
	 */
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + sid;//比较学号
		result = prime * result + ((sname == null) ? 0 : sname.hashCode());//比较姓名
		result = prime * result + ((ssex == null) ? 0 : ssex.hashCode());//性别
		return result;
	}
	
	@Override
	public boolean equals(Object obj) {
		//如果当前对象与obj对象是否相等,如果相等返回true
		//true:集合中存在相同的元素
		//false:集合中不存在相同的元素
		if (this == obj)
			return true;
		//obj对象为空,返回false
		if (obj == null)
			return false;
		//当前类对象与obj的类对象不相等,返回false
		if (getClass() != obj.getClass())
			return false;
		Student other = (Student) obj;
		//返回true:集合中存在相同的对象
		//返回false:集合中不存在相同的对象
		if(this.getSname().equals(other.getSname()))
			return true;
		return true;
	} 
	@Override
	public String toString() {
		return "Student [sid=" + sid + ", sname=" + sname + ", ssex=" + ssex + "]";
	}
}

注:当前实体类按顺序流程执行,先执行hashcode方法,再执行equals方法,那我给大家再来讲一下这个hashcode是用来干什么的。
hashcode是用于比较属性值是否相同。讲一下我实体类的逻辑哈。
hashcode比较后,如果一个或多的属性不相同就视为一个全新的对象,允许添加,不执行equals方法。
hashcode后,如果所有的属性都相同,再按流程执行我的equals方法,我这里只比较学生姓名是否相同。大家注意,看我写的注释,如果相同必须返回true才能达到判断的目的。