interface Set
- 无序、无下标、元素不能重复(当插入新元素时,会调用euqals进行比较)
- 方法:全部继承自Collection中的方法
- Set集合继承Collection接口,方法全部来自Collection接口,自身没有定义其他方法。
- Set接口主要两个实现类为HashSet、TreeSet。
- Set集合中的元素不按特定顺序排序。因此无法向list一样根据索引获取数据。
- 引用到堆上同一个对象的两个引用是相等的。如果对两个引用调用hashCode方法,会得到相同的结果,如果对象所属的类没有覆盖Object的hashCode方法的话,hashCode会返回每个对象特有的序号(java是依据对象的内存地址计算出的此序号),所以两个不同的对象的hashCode值是不可能相等的。
Set下几个重要的实现类与接口
- HashSet(类)
- LinkedHashSet(类)
- SortedSet(接口)下的TreeSet(class )
- Class HashSet【重点】:
- 存取HashSet集合中的元素,是根据哈希码来存取。HashSet根据哈希码来确定元素在集合中存储的位置(内存地址)
- HashSet不能保证迭代顺序,且允许元素为null
- 比较两个HashSet集合是否相同,先比较hasCode()返回的值是否相同,在使用equals()方法比较两个HashSet存储位置是否相同。如果满足以上两个条件,则HashSet集合相同。
- hasCode()和equals()方法必须一起使用,以保证判断HashSet一致性。
- 无参构建初始容量16 和负载因子0.75
- 线程不安全,存取速度快。底层是以hash表实现的。
public class TestHashSet{
public static void main(String[] args){
HashSet<String> hashset = new HashSet<String>();
hashset.add("中国");
hashset.add("美国");
hashset.add("日本");
hashset.add("英国");
System.out.println(hashset.add("中国")); // 输出false 不重复
//System.out.println(map);
//清空HashSet中的所有元素
//hashset.clear();
System.out.println(hashset);
//删除指定名称的元素
hashset.remove("日本");
System.out.println(hashset);
//使用迭代器遍历HashSet中的所有元素
Iterator iterator = hashset.iterator();
while (iterator.hasNext()){
System.out.println("遍历HashSet中的所有元素: "+iterator.next());
}
//获取HashSet集合中的元素个数
hashset.size();
}
}
- HashSet如何去重
1)HashSet底层使用的是HashMap类,即是使用
ctrl+shift+o快速导入包
哈希码不唯一,两个不同对象,巧合版的哈希码相同,HashSet怀疑两个对象对不对就是相同对象,调用
当存入元素的哈希码相同时,会调用equals进行确定,如结果为true,则拒绝后者存入
HashCode比较是否相同,如果相同,表示可能是重复对象,先调==再调equals
euqals二次确认
LinkedHashSet:
- 底层使用LinkedHashMap(链表结构)存储,按照链表进行存储,既可保留元素的插入顺序
- LinkedHashSet 是 Set 的一个具体实现,其维护着一个运行于所有条目的双重链接列表。此链接列表定义了迭代顺序,该迭代顺序可为插入顺序或是访问顺序。
- LinkedHashSet 继承与 HashSet,并且其内部是通过 LinkedHashMap 来实现的。有点类似于我们之前说的LinkedHashMap 其内部是基于 Hashmap 实现一样,不过还是有一点点区别的。
- 如果需要迭代的顺序为插入顺序或者访问顺序,那么 首先考虑LinkedHashSet
- 除了内部存储,可保留元素的插入顺序以外使用方法与HashSet没什么区别
Interface SortedSet
class TreeSet
- 实现了SortedSet接口,要求必须可以对元素排序。
- 所有插入元素,必须实现Comparab方法mpareTofangfa
- 根据compareTo方法返回0作为去重的依据,(意味重复)
- TreeSet集合中的元素是有顺序的,如果要排序直接使用TreeSet
- TreeSet的使用和其他集合差不多
- 红-黑树的数据结构,默认对元素进行自然排序(String)。如果在比较的时候两个对象返回值为0,那么元素重复。
红黑树算法的规则: 左小右大。
import java.util.TreeSet;
public class TestTreeSet {
public static void main(String[] args) {
TreeSet<String> tsb=new TreeSet();
tsb.add("张三");
tsb.add("李四");
tsb.add("王五");
tsb.add("赵六");
tsb.add("黑七");
System.out.println("树集合"+tsb);
System.out.println("树集合的第一个元素"+tsb.first());
System.out.println("树集合最后一个 元素"+tsb.last());
System.out.println("头(李四)"+tsb.headSet("李四"));
System.out.println("尾(李四)"+tsb.tailSet("李四"));
System.out.println("ceiling(四)"+tsb.ceiling("四"));
// 遍历迭代
Iterator<String> iterator = tsb.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
}
}
既然TreeSet可以自然排序,那么TreeSet必定是有排序规则的。
1:让存入的元素自定义比较规则。
2:给TreeSet指定排序规则。
方式一:元素自身具备比较性
元素自身具备比较性,需要元素实现Comparable接口,重写compareTo方法,也就是让元素自身具备比较性,这种方式叫做元素的自然排序也叫做默认排序。
方式二:容器具备比较性
当元素自身不具备比较性,或者自身具备的比较性不是所需要的。那么此时可以让容器自身具备。需要定义一个类实现接口Comparator,重写compare方法,并将该接口的子类实例对象作为参数传递给TreeMap集合的构造方法。
注意:当Comparable比较方式和Comparator比较方式同时存在时,以Comparator的比较方式为主;
注意:在重写compareTo或者compare方法时,必须要明确比较的主要条件相等时要比较次要条件。(假设姓名和年龄一直的人为相同的人,如果想要对人按照年龄的大小来排序,如果年龄相同的人,需要如何处理?不能直接return 0,因为可能姓名不同(年龄相同姓名不同的人是不同的人)。此时就需要进行次要条件判断(需要判断姓名),只有姓名和年龄同时相等的才可以返回0.)
通过return 0来判断唯一性。
因为字符串实现了一个接口,叫做Comparable 接口,所以字符串默认输出是按升序排列字符串重写了该接口的compareTo 方法,所以String对象具备了比较性.那么同样道理,我的自定义元素(例如Person类,Book类)想要存入TreeSet集合,就需要实现该接口,也就是要让自定义对象具备比较性.
存入TreeSet集合中的元素要具备比较性.
比较性要实现Comparable接口,重写该接口的compareTo方法
TreeSet属于Set集合,该集合的元素是不能重复的,TreeSet如何保证元素的唯一性
通过compareTo或者compare方法中的来保证元素的唯一性。
添加的元素必须要实现Comparable接口。当compareTo()函数返回值为0时,说明两个对象相等,此时该对象不会添加进来。
比较器接口
----| Comparable
compareTo(Object o) 元素自身具备比较性
----| Comparator
compare( Object o1, Object o2 ) 给容器传入比较器
TreeSet集合排序的两种方式:
一、让元素自身具备比较性。
也就是元素需要实现Comparable接口,覆盖compareTo 方法。
这种方式也作为元素的自然排序,也可称为默认排序。
二、让容器自身具备比较性,自定义比较器。
- 定义一个类实现Comparator 接口,覆盖compare方法。
- 并将该接口的子类对象作为参数传递给TreeSet集合的构造函数。
- 当Comparable比较方式,及Comparator比较方式同时存在,以Comparator比较方式为主。