如何使用set集合去重
我们都知道,set集合是无序的,这样也导致set集合里面的元素是不能重复的,因为这一个特性,所以我们经常用set集合进行去重操作,我们下面以一个简单的例子说明set集合是如何进行去重的。
创建去重对象
首先,我们需要创建去重的对象,这里我创建一个Student类。为了方便,我没有对此类进行封装,同时写出该类的全参构造方法,方便后面的赋值。同时重写toString()方法,方便后面打印的效果,否则默认的toString()打印的是地址,然后重写equals()方法和hashCode()方法,否则后面进行比较的是哈希值,哪怕后面的名字,年龄,性别都相同也会因为哈希值不同而导致判断不同,重写之后只要名字,年龄,性别都相同,那么值就是相同的。
public class Student {String name;//姓名int age;//年龄char sex;//性别public Student(String name, int age, char sex) {this.name = name;this.age = age;this.sex = sex;}
//重写toString()方法 IDEA使用快捷键Alt+insert,选择toString即可完成重写@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +", sex=" + sex +'}';}
//重写equals()方法和hashCode()方法 IDEA使用快捷键Alt+insert,选择equals() and hashCode()@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Student student = (Student) o;return age == student.age && sex == student.sex && Objects.equals(name, student.name);}@Overridepublic int hashCode() {return Objects.hash(name, age, sex);}
}
创建集合对象
因为set是一个接口,所以不能创建对象,我们通过set的实现类Hashset以多态形式进行创建
public class TestSet {public static void main(String[] args) {HashSet<Student> set = new HashSet<>();//创建集合对象,泛型为我们去重对象StudentStudent s1 = new Student("张三", 30, '男');//创建Student对象并录入值Student s2 = new Student("李四", 33, '男');Student s3 = new Student("张三", 30, '男');Student s4 = new Student("王五", 37, '男');set.add(s1);//将Student类型的值添加到集合里set.add(s2);set.add(s3);set.add(s4);System.out.println(set);//输出集合}
}
输出结果
我们可以发现,集合里面有三组数据,明明我们添加了4个Student类型数据,为什么集合里只有3个,原因是set集合不允许重复的元素,s1和s3相同,所以只保存一次,以此来达到去除重复元素的效果
@EqualsAndHashCode注解
一、回顾下==和equals的区别
如上图所示,简单来说,==是判断两个变量或实例是不是指向同一个内存空间,equals是判断两个变量或实例所指向的内存空间的值是不是相同。
二、再复习下equals()和hashCode()的关系
重写equals()
大部分使用场景里面,2个对象比较,更多的是关注对象的各个字段值是否相等。这时候就需要重写equals()方法。
重写hashCode()
为什么需要重写hashcode()呢?因为我们不知道对象在内存中的存放方式。
试想一下,如果有10000个元素,用遍历方式去寻找的话,效率就太低了;为了解决这一问题,哈希算法诞生了。
哈希算法的核心思想是:
将集合分成若干个存储区域(可以看成一个个桶),每个对象可以计算出一个哈希码,可以根据哈希码分组,每组分别对应某个存储区域,这样一个对象根据它的哈希码就可以分到不同的存储区域(不同的区域)。
理想情况下我们只需要比较hash值,就可以确定对象是否相等;但是,学过数据结构的都会知道哈希冲突这个概念,简单理解就是多个对象的哈希值可能相等,所以就需要我们再比较哈希值的基础之上,在进行equals()方法比较;
综上所述,元素比较的流程就是:先比较哈希值,再调用equals()。
这也是为什么equals()方法要和hashcode()一起重写;因为equals()中需要比较哈希值,而哈希值的生成方式又涉及hasdcode()方法。
三、来看看EqualsAndHashCode(lombok)
@EqualsAndHashCode
默认对类的所有字段实现equals()和hashCode()方法
@EqualsAndHashCode(of={“id”, “age”}, exclude = {“name”})
指定字段,排除字段
@EqualsAndHashCode(callSuer=true)
覆盖父类字段
四、来看看@Data
简单来说,@Data就是以下5个注解的集合。但是如果需要自定义一些特征,就需要分别使用各个注解。
/*** @see Getter* @see Setter* @see RequiredArgsConstructor* @see ToString* @see EqualsAndHashCode* @see lombok.Value*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface Data {