一,set:
是Collection的子接口,一个不包含重复元素的集合,set集合提供的方法与父接口Collection的方法完全一致,即没有关于下标的操作方法
set接口有两个常用的子实现类HashSet,TreeSet
二,HashSet:
HashSet实现了Set接口,底层是hash表(实际上底层是HashMap),该类不允许重复元素,不保证迭代顺序,即无序,(插入顺序和遍历顺序不一致)。
1,构造方法:
HashSet()
构造一个新的空 set,其底层 HashMap 实例的默认初始容量是 16,加载因子是 0.75。
HashSet(Collection<? extends E> c)
构造一个包含指定 collection 中的元素的新 set。
HashSet(int initialCapacity)
构造一个新的空 set,其底层 HashMap 实例具有指定的初始容量和默认的加载因子(0.75)。
HashSet(int initialCapacity, float loadFactor)
构造一个新的空 set,其底层 HashMap 实例具有指定的初始容量和指定的加载因子。
2,方法:
HashSet类中的方法与父接口Set接口中的方法一致,即又跟Collection接口中的方法一致,所有的都能用
boolean add(E e)
如果此 set 中尚未包含指定元素,则添加指定元素。
boolean remove(Object o)
如果指定元素存在于此 set 中,则将其移除。
int size()
返回此 set 中的元素的数量(set 的容量)。
HashSet<Object> hashSet = new HashSet<>();
//空参
//System.out.println(hashSet);
// hashSet.add(1);
// hashSet.add(2);
// hashSet.add(3);
// hashSet.add(1);
// hashSet.add("..");
// hashSet.add("邓");
// hashSet.add("森");
// hashSet.add("洋");
//重复元素去除,无序输出
//System.out.println(hashSet);
//迭代遍历
// Iterator<Object> iterator = hashSet.iterator();
// while (iterator.hasNext()){
// Object next = iterator.next();
// System.out.print(next+" ");
// }
//foreach遍历
// for (Object o: hashSet
// ) {
// System.out.print(o+" ");
// }
//移除元素
// boolean remove = hashSet.remove("..");
// System.out.println(remove);
//返回集合容量
// int size = hashSet.size();
// System.out.println(size);
//构造方法HashSet(Collection o),去除ArrayList集合中的重复元素
// ArrayList<Object> list = new ArrayList<>();
// list.add(1);
// list.add(1);
// list.add(2);
// list.add(2);
// list.add(3);
// list.add(3);
// list.add(4);
// list.add(4);
// HashSet<Object> hashSet1 = new HashSet<>(list);
// System.out.println(hashSet1);
//判断是否为空
//System.out.println(hashSet.isEmpty());
//判断是否包含指定元素
// boolean contains = hashSet.contains(1);
// System.out.println(contains);
//判断是否包含所有元素
// boolean b = hashSet.containsAll(hashSet);
// System.out.println(b);
//将指定集合放到hashset集合中,去除重复
// boolean b = hashSet.addAll(list);
// System.out.println(b);
// System.out.println(hashSet);
//清空集合
// hashSet.clear();
// System.out.println(hashSet);
//移除集合HashSet中的ArrayList集合的元素
// boolean b = hashSet.removeAll(list);
// System.out.println(b);
// System.out.println(hashSet);
3,扩容:
HashSet底层是Hash表,其实是HashMap,初始容量16,加载因子 0.75,扩容的阈值 = 容量 * 0.75 ,超过阈值就触发扩容,扩容2倍,初始容量和加载因子可以通过构造方法创建时修改的。
4,去重原理:
1,调用add(E,e)方法时,会在底层调用元素e的hashcode方法来获得对象的地址值
2,如果地址值不一样,直接存储
3,如果地址值一样,会再调用元素的equals方法判断内容是否一样
4,如果equals不一样,那么就存储,如果equals判断为true,那么去重
三,LinkedHashSet:
LinkedHashSet既有HashSet的去重又有Linked结构有序的特性,即存储在LinkedHashSet中的元素既有不允许重复,又能保证迭代顺序
LinkedHashSet<Integer> integers = new LinkedHashSet<>();
//既有序,又去重
integers.add(111);
integers.add(222);
integers.add(333);
integers.add(12);
integers.add(222);
System.out.println(integers);
}
五,TreeSet:
TreeSet是基于基于TreeMap的NavigableSet实现,可以使用元素的自然顺序对元素进行排序或者根据创建的set时提供的Comparator进行排序,具体取决于使用的构造方法,即TreeSet会对存储的元素排序,当然也会去重
1,演示方法:
构造方法:
TreeSet()
构造一个新的空set,set根据其元素的自然顺序进行排序。
TreeSet(Comparator<? super E> comparator)
构造一个新的空TreeSet,它根据指定比较器进行排序。
方法:
有常规的集合的方法,还有一些基于数据结构能排序的特性才有的特殊方法,取值范围的(ceiling(),floor(),lower(),higher(),),首尾取值的(first(),last())
TreeSet<Integer> treeSet= new TreeSet<>();
//去重(不能存储重复元素)并排序(升序)
treeSet.add(3);
treeSet.add(2);
treeSet.add(4);
treeSet.add(1);
treeSet.add(3);
//System.out.println(treeSet);
for (Integer integer : treeSet) {
//System.out.println(integer);
}
//获得排序后的第一个
//System.out.println(treeSet.first());
//获得排序后的最后一个
//System.out.println(treeSet.last());
//System.out.println(treeSet);
//获取并移除排序后的第一个
//System.out.println(treeSet.pollFirst());
//获取并移除排序后的最后一个
//System.out.println(treeSet.pollLast());
//集合中已经不存在拿出的元素
//System.out.println(treeSet);
//返回此set中严格小于给定元素的最大元素
System.out.println(treeSet.lower(100));
2,去重原理:
前提知识: TreeSet底层是TreeMap,TreeMap是红黑树,是一种平衡二叉树(AVL)
练习1:新建User类(age,name),创建TreeSet集合,创建多个User对象,将user对象存入TreeSet集合,实现去重排序,1) 年龄和姓名一致则去重 2) 按照年龄从小到大排序
TreeSet<User> set = new TreeSet<>( );
set.add(new User(18,"厄加特"));
// 运行报错ClassCastException 无法转成Comparable接口
Comparable接口,强行对实现它的每个类的对象进行整体排序,这种排序被称为类的自然排序.
实现这个接口,需要重写comparTo方法,该方法返回值决定了是升序,降序还是去重!
该comparTo(T t)方法运行时 , this指代当前正在调用该方法的对象,参数T就是之前已经存在的元素.
- 返回值 0 ,意味着此元素(正在存储的元素)和之前的元素相同,即不存储,则去重
- 返回值正整数,意味着此元素 大于之前的元素, 放在该节点的右边
- 返回值负整数,意味着此元素小于之前的元素,放在该节点的左边
最后都存储完毕时,取值时采用中序遍历(从根节点开始按照左,中,右的顺序读取)
public class User implements Comparable<User>{
// 属性和方法...
/**
* this 是指代正在存储的元素
* o 是之前存储的元素
*/
@Override
public int compareTo(User o) {
System.out.println("此对象--> " + this);
System.out.println("指定对象--> " + o);
// 姓名和年龄相同返回0,即去重不存储
if (this.name.equals(o.getName()) && this.getAge() - o.getAge() == 0) {
return 0;
}
// 年龄相同返回1,即保留下来的不去重的意思
// 年龄不同的话就正常相减,返回负数或正数
return this.getAge() - o.getAge() == 0 ? 1 : this.getAge() - o.getAge();
}
六,总结:
HashSet方法与父接口Collection中的方法一致,直接用,面试题:HashSet底层(HashMap),扩容,去重原理
LinkedHashSet 了解:
TreeSet底层树结构了解就行,只需要知道要想去重排序,必须要实现接口重写方法,返回0去重,返回负放左子树,返回正放右子树