Set集合怎么使用呢?
目录
Set接口
特点:
Set: 无序,不重复 (无序:存入和拿出来的顺序不同所以不能使用下标)
遍历:
foreach , 迭代器
扩容:
初始容量 16 ,负载因子 0.75 ,扩容增量1倍
实现:
对于 HashSet 而言,它是基于 HashMap 实现的,HashSet 底层使用 HashMap 来保存所有元素,因此 HashSet 的实现比较简单,相关 HashSet 的操作,基本上都是直接调用底层 HashMap 的相关方法来完成,我们应该 为保存到 HashSet 中的对象覆盖 hashCode() 和 equals()
已知实现接口有:
Serializable, Cloneable, Iterable<E>, Collection<E>, Set<E>
已知子类:
JobStateReasons, LinkedHashSet
1. HashSet
特点:
- 它存储 唯一元素 并 允许空值 依据对象的 hashcode 来确定该元素是否存在
- 由HashMap支持
- 不保持插入顺序
- 非线程安全
- 性能参数:初始容量,负载因子 默认值: 初始容量16,负载因子0.75
- 示例:new HashSet<>(20, 0.5f);
- 思考:
1. 如何给ArrayList集合 去重
2. set有ArrayList中存在的 通过下标删除 ,或foreach循环删除时的问题吗? 为什么
3. set是否存在List删除,传入整数需要区分是基本型还是对象型的问题,【例如:list.remove(2)】,为什么?
4. HashSet是如何实现的?
代码运用:
如何把ArrayList中重复的元素去掉(去重),方法有很多,大佬们可以自己试着写几个,这里提供一个比较简单快速的方法: 使用 HashSet去重
public class SetDemo { private List<Integer> list = new ArrayList<>(); @BeforeAll public void setup() { set.add(1); set.add(1); set.add(2); set.add(2); set.add(3); set.add(3); } @Test public void test01() { List<Integer> tmp = new ArrayList<>(new HashSet<Integer>(list)); System.out.println(tmp); } }
输出结果是123(ArrayList是可以存放重复元素的,但是这里使用了HashSet去重)
1、新建一个Set集合并放入元素
public class SetDemo { private Set<Integer> set = new HashSet<>(); @BeforeAll public void setup() { set.add(1); set.add(1); set.add(2); set.add(4); set.add(5); set.add(3); } }
2、可以使用下面两种方法遍历其中的元素,由于 HashSet中只能存储不重复的对象 ,所以输出时会自动把重复的元素去重
@Test public void test02() { for(Integer e: set) { System.out.println(e); } } //使用迭代器 @Test public void test03() { Iterator<Integer> it = set.iterator(); while(it.hasNext()) { System.out.println(it.next()); } }
3、 set.remove(i)中传入的是元素 ,这是由于HashSet 不保证插入顺序, 没有下标概念,所以只能传入元素
@Test public void test05() { set.remove(3); System.out.println(set); }
删除的是第一步里面Set集合里面的元素3,输出的是1245
2. TreeSet
特点:
- 是一个包含 有序 的且 没有重复元素 的集合
- 作用是提供有序的Set集合,自然排序或者根据提供的Comparator进行排序
- TreeSet是基于TreeMap实现的
示例:
测试数据
1. 默认自然排序
2. 自定义比较器:1. 通过构造函数传入比较器 2. 实现排序接口
代码运用:
创建一个学生类并实现编比较器接口
public class Student implements Comparable<Student>{ private Integer sid; private String sname; private int age; public Student(Integer sid, String sname, int age) { super(); this.sid = sid; this.sname = sname; this.age = age; } public Integer getSid() { return sid; } public void setSid(Integer sid) { this.sid = sid; } public String getSname() { return sname; } public void setSname(String sname) { this.sname = sname; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
还需要在这个学生类中实现 hashCode 和 equals 方法:
/* *hashCode可以将学号名字努力转成唯一的数字,相对于身份证 */ @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + age; result = prime * result + ((sid == null) ? 0 : sid.hashCode()); result = prime * result + ((sname == null) ? 0 : sname.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; Student other = (Student) obj; if (age != other.age) return false; if (sid == null) { if (other.sid != null) return false; } else if (!sid.equals(other.sid)) return false; if (sname == null) { if (other.sname != null) return false; } else if (!sname.equals(other.sname)) return false; return true;//学号名字年龄都相等才是同一个学生 } @Override public String toString() { return "Student [sid=" + sid + ", sname=" + sname + ", age=" + age + "]"; } /** * 实现Comparable<Student>接口后需要重写的方法 * 根据年龄排序,年龄相同则比较学号,默认是升序 */ @Override public int compareTo(Student o) { if(this.getAge()-o.getAge()==0) { return this.getSid()-o.getSid(); } return this.getAge() - o.getAge(); }
然后再使用ThreeSet
@Test public void test04() { TreeSet<Student> stu = new TreeSet<>(); stu.add(new Student(1,"zs", 18)); stu.add(new Student(1,"zs", 18)); stu.add(new Student(2,"ls", 19)); stu.add(new Student(4,"lihao", 10)); stu.add(new Student(7,"lihao", 18)); stu.add(new Student(5,"zengfanyan", 20)); stu.add(new Student(3,"we", 30)); for(Student s: stu) { System.out.println(s); } }
运行输出结果:
感谢收看鸭~