Set接口

Set接口

java.util.Set接口和java.util.List接口一样,同样继承自Collection接口,它与Collection接口中的方法基本一致,并没有对Collection接口进行功能上的扩充,只是比Collection接口更加严格了。与List接口不同的是,Set接口中元素无序,并且都会以某种规则保证存入的元素不出现重复。

tips:Set集合取出元素的方式可以采用:迭代器、增强for。

1 HashSet集合介绍

java.util.HashSetSet接口的一个实现类,它所存储的元素是不可重复的,并且元素都是无序的(即存取顺序不一致)。java.util.HashSet底层的实现其实是一个java.util.HashMap支持。

HashSet是根据对象的哈希值来确定元素在集合中的存储位置,因此具有良好的存取和查找性能。保证元素唯一性的方式依赖于:hashCodeequals方法。

我们先来使用一下Set集合存储,看下现象,再进行原理的讲解:

 public class HashSetDemo {
     public static void main(String[] args) {
         //创建 Set集合
         HashSet<String>  set = new HashSet<String>();
 ​
         //添加元素
         set.add(new String("cba"));
         set.add("abc");
         set.add("bac"); 
         set.add("cba");  
         //遍历
         for (String name : set) {
             System.out.println(name);
         }
     }
 }

输出结果如下,说明集合中不能存储重复元素:

 cba
 abc
 bac

tips:根据结果我们发现字符串"cba"只存储了一个,也就是说重复的元素set集合不存储。

2 HashSet集合存储数据的结构(哈希表)

什么是哈希表呢?

JDK1.8之前,哈希表底层采用数组+链表实现,即使用链表处理冲突,同一hash值的链表都存储在一个链表里。但是当位于一个桶中的元素较多,即hash值相等的元素较多时,通过key值依次查找的效率较低。而JDK1.8中,哈希表存储采用数组+链表+红黑树实现,当链表长度超过阈值(8)时,将链表转换为红黑树,这样大大减少了查找时间。

简单的来说,哈希表是由数组+链表+红黑树(JDK1.8增加了红黑树部分)实现的。

JDK1.8引入红黑树大程度优化了HashMap的性能,那么对于我们来讲保证HashSet集合元素的唯一,其实就是根据对象的hashCode和equals方法来决定的。如果我们往集合中存放自定义的对象,那么保证其唯一,就必须复写hashCode和equals方法建立属于当前对象的比较方式。

3 HashSet存储自定义类型元素

给HashSet中存放自定义类型元素时,需要重写对象中的hashCode和equals方法,建立自己的比较方式,才能保证HashSet集合中的对象唯一

创建自定义Student类

 public class Student {
     private String name;
     private int age;
 ​
     public Student() {
     }
 ​
     public Student(String name, int age) {
         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 boolean equals(Object o) {
         //比较地址,如果o的地址和this的相同代表地址相同,直接true
         if (this == o)
             return true;
         //如何o为空,或者比较的数据的类型不同直接flase
         if (o == null || getClass() != o.getClass())
             return false;
         Student student = (Student) o;
         //使用objects的equals可以避免空指针安全
         return age == student.age &&
                Objects.equals(name, student.name);
     }
 ​
     @Override
     public int hashCode() {
         return Objects.hash(name, age);
     }
 }
 public class HashSetDemo2 {
     public static void main(String[] args) {
         //创建集合对象   该集合中存储 Student类型对象
         HashSet<Student> stuSet = new HashSet<Student>();
         //存储 
         Student stu = new Student("于谦", 43);
         stuSet.add(stu);
         stuSet.add(new Student("郭德纲", 44));
         stuSet.add(new Student("于谦", 43));
         stuSet.add(new Student("郭麒麟", 23));
         stuSet.add(stu);
 ​
         for (Student stu2 : stuSet) {
             System.out.println(stu2);
         }
     }
 }
 执行结果:
 Student [name=郭德纲, age=44]
 Student [name=于谦, age=43]
 Student [name=郭麒麟, age=23]

4 LinkedHashSet

我们知道HashSet保证元素唯一,可是元素存放进去是没有顺序的,那么我们要保证有序,怎么办呢?

在HashSet下面有一个子类java.util.LinkedHashSet,它是链表和哈希表组合的一个数据存储结构。

演示代码如下:

 public class LinkedHashSetDemo {
     public static void main(String[] args) {
         Set<String> set = new LinkedHashSet<String>();
         set.add("bbb");
         set.add("aaa");
         set.add("abc");
         set.add("bbc");
         Iterator<String> it = set.iterator();
         while (it.hasNext()) {
             System.out.println(it.next());
         }
     }
 }
 结果:
   bbb
   aaa
   abc
   bbc

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值