一、Set
1.1介绍
- Set是Collection的子接口
- 规定所存储的元素是不允许重复,且无序
- HashSet的无序是将存储的元素随机排序
- TreeSet的无序是指将存储的元素给排序了
- Set接口一般常用两个实现类
- HashSet,存储的元素是无序且去重
- TreeSet,存储的元素是去重且排序
二、HashSet
是接口的实现类,存储的元素是无序且去重,不保证线程安全
2.1方法演示
HashSet() 空参构造,创建空集合
HashSet(Collection c)创建带元素的集合,里面的初始值就是传入的集合
方法都是常规方法,没有关于下标的操作
- boolean add();添加时返回值是boolean型,判断里面是否有,有就返回false
- 同样List有的Set也有,如:size、isEmpty、contains、clear
- 加入的元素没有顺序
2.2底层实现原理
- HashSet底层是HasnMap,而HashMap底层是哈希表
- 创建HashSet时就会创建HashMap
- 添加元素到HashSet也会put到Map中
- HashSet或者HashMap创建时,默认容量16,加载因子0.75
- 容量就是存储的个数
- 加载因子的作用是控制扩容的时机
什么时候触发扩容?
- 当存储的元素达到初始容量*加载因子时,即达到16×0.75 = 12,就会扩容,扩容成原来的2倍
可以通过调整初始容量和加载因子改变性能,建议不要修改
2.3去重原理
- 先调用存储的元素hashcode方法,获得地址值
- 然后与集合中的元素的地址值判断,如果不一样直接存储
- 如果存储的元素地址值与集合中存在的元素的地址值一样,再比较equals方法,判断对象属性是否相同
- 如果equals也判断相同,即认为重复,不存储
- 如果equals也判断相同,即认为不重复,存储
- HashSet会去重,想要去重记得重写hashCode和equals方法即可,至于原理,面试的时候讲出来就行了
三、TreeSet
是Set集合的实现类,也是不允许重复元素,但存储的元素有序会对存储的元素默认按照自然顺手排序,也不保证线程安全
TreeSet底层是TreeMap
-
compareTo()方法的返回值决定了元素的顺序以及是否去重
- 返回值为0,直接去重
- 返回值为负数,放根节点左侧
- 返回值为正数,放根节点右侧
- 存储完,树按照中序排序遍历元素
o是二叉树结构上以前存储过的元素
- this是当前的元素
3.2排序原理
- 要利用TreeSet排序,存储的元素必须实现Comparable接口,重写从mparTo方法
- 当调用add方法存储元素时,会调用元素ComparTo进行运算
- 返回值为0,直接去重
- 返回值为负数,放根节点左侧
- 返回值为正数,放根节点右侧
总结:使用TreeSet进行排序去重一定要实现Comparable接口,重写comparTo方法根据情况可以去写算法,用法不太多
3.3自然排序&比较器排序
自然排序其实就是指实现Comparble接口,创建TreeSet集合时不指定排序规则,默认就是这种自然排序,(实现Comparable接口,重写compareTo方法)
比较器排序,在创建集合时传入自定义的比较器对象,存储元素时就会使用自定义的方法实现排序,(子自定义比较器类时,实现的是Imparator重写的是compare方法)
//自定义比较器类
public class MyIntegerCompare implements Comparator<Integer>{ @Override public int compare(Integer o1, Integer o2) { return 1; } }
//定义测试类
public static void main(String[] args) { TreeSet<Integer> integers = new TreeSet<Integer>(new MyIntegerCompare()); integers.add(1); integers.add(4); integers.add(4); integers.add(2); integers.add(54); for (Integer i : integers) { System.out.println(i); } }
总结:
- 自然排序简单,且jdk中默认使用这种,一般从小到大
- 比较器排序,更灵活,可以自定义规则
- 自然排序需要类实现Comparable接口的,但是如果说源码无法改动,即无法实现Comparable接口完成排序时,就可以使用比较器排序
四、Map
4.1介绍
Map是一种映射关系的集合,能从键映射到值,是一种特殊集合,一次存储一对元素(键值对),即Map是双列集合
ps:映射理解就是查找
- Map中不能有键重复,值能重复,一个键只能有一个值(键找值)
- Map中无法通过值找键
- Map接口体重三种集合试图,允许以
Map一般常用的两个实现子类:HashMap、TreeMap
4.2HashMap[重点]
HashMap是Map实现
- 底层是基于Hash表(jdk1.8之后底层是数组+红黑树+链表)
- 允许存储空值空键
- HashMap不保证线程安全
- Hashtable是线程安全的,不允许null值null键
4.3方法
- map.put(); 添加元素,有返回值是此键所对应的之前的value,之前没有就返回null,输出元素是无序的
public static void main(String[] args) { //创建空的map集合 HashMap<Integer, String> map = new HashMap<>(); //添加元素(键不允许重复,值可以重复 String v1 = map.put(2, "二"); System.out.println(v1); String v2 = map.put(2, "贰"); System.out.println(v2); String v3 = map.put(1, "一"); System.out.println(v3); //输出结果 System.out.println(map); }
v get(Object key) 通过键找值,返回是值
map.containsKey(Key k) 判断是否包含某个键
map.containsKey(Value v) 判断是否包含某个值
map.size() 集合大小(尺寸),元素个数
map.clear() 清空集合
v remove(Object k) 根据键删除整个键值对,返回值是键对应的值
4.3迭代遍历
Map集合没有提供直接的遍历Map集合的方法,但是提供了
-
键集 Set keySet(),专门遍历键
/** * 通过键来遍历 * 首先通过键来将所有键来存储到Set集合中,因为Set是去重的,而键也是不重复的 * 其次用遍历来输出所有的键 */ Set<Integer> keySet = map.keySet(); for (Integer key:keySet){ System.out.println(key); }
-
值集Collection value,专门遍历值
/**
* 通过值来遍历
* 先将所有值存储到Collection中,因为值能重复,如果放到Set中就会去重
* 最后同样也要遍历输出
*/
Collection<String> values = map.values();
for (String v:values){
System.out.println(v);
}
- 键值映射集Set<Map.Entry<K,V>>entrySet,专门遍历键值对
/**
* 通过键值对来一起输出
* 将得到键值对来放进Set的映射集Map.Entry<K,V>就是用来存储一对键值对的
* 最后同样也是遍历
*/
Set<Map.Entry<Integer,String>> entrySet = map.entrySet();
for (Map.Entry<Integer,String> entry:entrySet){
Integer key = entry.getKey();
String value = entry.getValue();
System.out.println(key+"="+value);
}