赞
踩
目录
Set继承自Collection接口,没有特殊的方法
Set集合的特点
底层数据结构为HashMap哈希表
元素放入时是无序的,指的是内存空间不连续,因为元素在set中的位置是由该元素的HashCode决定的。
而且,HashMap每次扩容都可能导致元素重新排布,所以元素的位置是不确定的。
(1)继承结构
HashSet继承了AbstractSet类,实现了Set、克隆、序列化接口。
AbstractSet有三个方法,提供了Set接口的基本实现
(2)成员变量
map:HashMap类型,初始没有赋值
PRESENT:Object类型,用来占位。HashSet只用HashMap的key存储数据,对应的value都是用同一个PRESENT占位。
(3)构造函数
有三个有参构造,一个无参构造
无参构造通过无参构造,创建了一个HashMap对象。
通过集合对象创建HashSet
也可以指定hashMap的指定初始容量和负载因子
总结
不管使用哪种构造方式,都会立刻创建一个HashMap对象。
(4)add()
直接调用hashMap的put()方法。
hashMap的put()方法,如果添加成功,会返回null。如果key值重复,会更新key对应的value,并返回旧的value值。
此处的add()方法,如果添加成功就会返回true。
(5)remove()
直接调用hashMap的remove()方法。
hashMap的remove()方法,如果删除成功,会返回被删除的value。
在元素类中重写hashCode方法和equals方法,依此来确保元素的唯一性
使用HashSet时,如果没有重写两个方法,则元素还是会重复录入,因为HashSet不知道判断两个对象相等的条件
重写时可以添加条件,比如name和age相等时,对象相等,则只会保留一个该数据的对象
如果存入的是字符串或整数等数据,则HashSet会自动判断唯一性
如果存入的是用户对象,则HashSet根据该对象的类中重写的hashCode方法和equals方法,来判断唯一性
示例 HashSet集合存储学生对象并遍历
学生类
- //定义学生类
- public class Student05 {
- private String name;
- private int age;
-
- public Student05() {
- }
-
- public Student05(String name, int age) {
- this.name = name;
- this.age = age;
- }
-
- //重写两个方法,如果学生对象的成员变量值相同,就认为是同一个对象
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- Student05 student05 = (Student05) o;
- return age == student05.age && Objects.equals(name, student05.name);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(name, age);
- }
- }
集合
-
- import java.util.HashSet;
-
- public class HashSetDemo01 {
- public static void main(String[] args) {
- HashSet<Student05> hs = new HashSet<Student05>();
-
- Student05 s1 = new Student05("张三", 20);
- Student05 s2 = new Student05("李四", 21);
- Student05 s3 = new Student05("王五", 23);
-
- Student05 s4 = new Student05("李四", 21);
-
- hs.add(s1);
- hs.add(s2);
- hs.add(s3);
- hs.add(s4);
-
- for (Student05 s : hs) {
- System.out.println(s.getName() + "," + s.getAge());
- }
-
- }
- }
LinkedHashSet概述
LinkedHashSet底层数据结构是哈希表和链表,根据元素的hashCode值来决定元素的存储位置,但它同时使用链表维护元素的次序,这样使得元素看起来是以插入的顺序保存的,也就是说当遍历集合LinkedHashSet集合里的元素时,集合将会按元素的添加顺序来访问集合里的元素。
输出集合里的元素时,元素顺序总是与添加顺序一致。但是LinkedHashSet依然是HashSet,因此它不允许集合重复。
TreeSet概述
TreeSet是SortedSet接口的实现类,TreeSet可以确保集合元素处于排序状态。
TreeSet内部实现的是红黑树,默认整形排序为从小到大。
不允许放入null值
TreeSet排序
存入TreeSet集合中的元素要具备比较性
比较性要实现Comparable接口,重写该接口的compareTo方法
TreeSet根据构造方法不同,分为自然排序(无参构造)和比较器排序(有参构造)
- 自然排序要求元素必须实现Compareable接口,并重写里面的compareTo()方法,元素通过比较返回的int值来判断排序序列,返回0说明两个对象相同,不需要存储
- 比较器排需要在TreeSet初始化是时候传入一个实现Comparator接口的比较器对象,或者采用匿名内部类的方式new一个Comparator对象,重写里面的compare()方法;
TreeSet两种构造方法:
方法名 | 说明 |
---|---|
TreeSet() | 根据其元素的自然排序进行排序 |
TreeSet(Comparator comparator) | 根据指定的比较器进行排序 |
排序详细做法
需求:比如要对Student对象排序,按年龄从小到大排,如果年龄一样,则按名字的自然顺序排
分析:对Student对象排序,有两种方式,第一种需要对Student类进行改造,即使用自然排序,第二种则需要另外写一个比较器类
自然排序
自然排序概述
用TreeSet集合存储对象,无参构造方法使用的是自然排序对元素进行排序
- 这个方法,是让元素自身具备比较性
- 自然排序,需要让元素所属的类实现Comparable接口,添加泛型,重写compareTo(T o)方法
- 当调用一个一个对象调用该方法与另一个对象进行比较时,obj1.compareTo(obj2)如果返回0表示两个对象相等;如果返回正整数则表明obj1大于obj2,如果是负整数则相反。
自然排序的使用
1.在Student类中,需要继承Comparable接口,并添加泛型,如果只是Student类之间的比较,则泛型为Student类型就可以
public class Student implements Comparable<Student>{}
2.在Student类中,重写compareTo方法,比较的类型还是它自己,Student类型
public int compareTo(Student06 s) {}
3.根据需要,添加比较器中的内容,有两种写法
因为是先按年龄排,年龄相等时再按姓名排,所以年龄为首要条件,姓名为次要条件
先写两个if一个return,如果大于返回1,等于返回0,小于直接返回-1
在符合的首要条件里覆盖掉返回0,写次要条件
- @Override
- public int compareTo(Student06 s) {
- //判断首要条件
- //大于返回1
- if(this.age>s.age){
- return 1;
- }
- //等于,判断次要条件
- if (this.age==s.age){
- return this.name.compareTo(s.name);
- }
- //小于返回-1
- return -1;
- }
这种写法把每种情况罗列且区分出来了,一目了然,而且可以很方便地修改比较条件。
比如原本是年龄升序排列,我要改成年龄降序,只需要把判断年龄条件之后执行的操作改成return -1即可
- @Override
- public int compareTo(Student06 s) {
- int num = this.age - s.age;
- int num2 = (num == 0) ? this.name.compareTo(s.name) : num;
- return num2;
- }
第二种写法显然更简洁,与第一种写法做的是同样的事情,但需要写出涉及比较的内容,有几层判断,定义几个int类型的返回值即可
自然排序的总结
不符合面向对象的思维
自然排序是对要排序的类直接操作,比较器的内容在被比较的类中,要更改条件,只能进入被比较的类中进行修改原理
这里的this,指的是当前被比较的对象,s则是指同类型的其他对象
TreeSet是红黑树(二叉树),比较器用来给元素定位。如果比较器返回0,则元素重复,不添加,如果返回1或-1,则元素存储在二叉树的左或右孩子
自制排序
自制排序概述
TreeSet集合有参构造方法使用比较器排序对元素进行排序
- 这个方法,是让容器具有比较性
- 当元素自身不具备比较性,或者自身具备的比较性不是所需要的。那么此时可以让容器自身具备。需要定义一个类实现接口Comparator,重写compare方法,并将该接口的子类实例对象作为参数传递给TreeMap集合的构造方法。
注意:当Comparable比较方式和Comparator比较方式同时存在时,以Comparator的比较方式为主;
注意:在重写compareTo或者compare方法时,必须要明确比较的主要条件相等时要比较次要条件。(假设姓名和年龄一直的人为相同的人,如果想要对人按照年龄的大小来排序,如果年龄相同的人,需要如何处理?不能直接return 0,因为可能姓名不同(年龄相同姓名不同的人是不同的人)。此时就需要进行次要条件判断(需要判断姓名),只有姓名和年龄同时相等的才可以返回0.)
通过return 0来判断唯一性。
由于Comparator是一个函数式接口,因此还可以使用Lambda表达式来代替Comparator子类对象。
自制排序的使用
1.首先需要写一个比较器类
public class MyComparator implements Comparator<Student> {}
2.在比较器类中重写compare方法
- public class MyComparator implements Comparator<Student> {
-
- @Override
- public int compare(Student s1, Student s2) {
- }
-
- }
3.通过已知的首要、次要方法,添加比较内容
- public class MyComparator implements Comparator<Student> {
-
- @Override
- public int compare(Student s1, Student s2) {
- //主要条件:学生年龄按从大到小排序
- int num = s2.getAge() - s1.getAge();
-
- //学生年龄相同,比较姓名是否一样
- int num2 = (num == 0) ? (s1.getName().compareTo(s2.getName())) : num;
- return num2;
- }
-
- }
4.创建TreeSet集合时,需要指明使用了哪个自制比较器类
TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>()){}
自制排序的总结
符合面向对象思想
无需改动被比较的类,只需要单独写一个比较器类即可,可以单独写,也可以在创建TreeSet时使用匿名内部类的方式添加
比较器类中可以调用被比较对象的所有参数,灵活比较各种东西
注意
大部分类在实现CompareTo(Object o)方法时,都需要将被比较对象obj强制类型转换成相同类型,因为只有相同的两个实例才会比较大小。
加入集合的类都必须实现Comparable接口,否则会引发ClassCastException异常。
不要修改已经存入集合的实例变量,这将导致它与其他对象的大小顺序发生改变,但TreeSet集合不会再次调整它们的顺序,这点和HashSet一样。
总结:如果希望TreeSet能正常工作,TreeSet只能添加同一种类型的对象
TreeSet如何确保唯一性
对于TreeSet集合而言,它判断两个对象是否相等的唯一标准是:两个对象通过compareTo(Object obj)方法比较是否返回0,如果是0则认为对象相等,否则认为不相等。
Set小结
Set具有与Collection完全一样的接口,因此没有任何额外的功能,不像前面有两个不同的List。实际上Set就是Collection,只 是行为不同。(这是继承与多态思想的典型应用:表现不同的行为。)Set不保存重复的元素。
TreeSet不允许放入null值,HashSet允许放入一个null值
适用场景分析:
HashSet是基于Hash算法实现的,其性能通常都优于TreeSet。为快速查找而设计的Set,我们通常都应该使用HashSet,在我们需要排序的功能时,我们才使用TreeSet。
List与Set的对比
Set:检索元素效率低下,删除和插入效率高,插入和删除不会引起元素位置改变。 List:和数组类似,List可以动态增长,查找元素效率高,插入删除元素效率低,因为会引起其他元素位置改变。
如何挑选合适的Collection集合
看到array,就要想到索引。
看到link,就要想到first,last。
看到hash,就要想到hashCode,equals.
看到tree,就要想到两个接口。Comparable,Comparator。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。