Queue
Queue:队列,先进先出的特性
PriorityQueue 是优先级队列,底层存储结构为 Object[],默认实现为小顶堆,每次出队最小的元素
构造方法:
-
public PriorityQueue()
:构造默认长度为 11 的队列(数组) -
public PriorityQueue(Comparator<? super E> comparator)
:利用比较器自定义堆排序的规则Queue<Integer> pq = new PriorityQueue<>((v1, v2) -> v2 - v1);//实现大顶堆
常用 API:
public boolean offer(E e)
:将指定的元素插入到此优先级队列中尾部public E poll()
:检索并删除此队列的头元素,如果此队列为空,则返回 nullpublic E peek()
:检索但不删除此队列的头,如果此队列为空,则返回 nullpublic boolean remove(Object o)
:从该队列中删除指定元素(如果存在),删除元素 e 使用 o.equals(e) 比较,如果队列包含多个这样的元素,删除第一个
Collections
java.utils.Collections:集合工具类,Collections 并不属于集合,是用来操作集合的工具类
Collections 有几个常用的API:
public static <T> boolean addAll(Collection<? super T> c, T... e)
:给集合对象批量添加元素public static void shuffle(List<?> list)
:打乱集合顺序public static <T> void sort(List<T> list)
:将集合中元素按照默认规则排序public static <T> void sort(List<T> list,Comparator<? super T> )
:集合中元素按照指定规则排序public static <T> List<T> synchronizedList(List<T> list)
:返回由指定 list 支持的线程安全 listpublic static <T> Set<T> singleton(T o)
:返回一个只包含指定对象的不可变组
public class CollectionsDemo { public static void main(String[] args) { Collection<String> names = new ArrayList<>(); Collections.addAll(names,"张","王","李","赵"); List<Double> scores = new ArrayList<>(); Collections.addAll(scores, 98.5, 66.5 , 59.5 , 66.5 , 99.5 ); Collections.shuffle(scores); Collections.sort(scores); // 默认升序排序! System.out.println(scores); List<Student> students = new ArrayList<>(); Collections.addAll(students,s1,s2,s3,s4); Collections.sort(students,new Comparator<Student>(){ }) } } public class Student{ private String name; private int age; }
Map
概述
Collection 是单值集合体系,Map集合是一种双列集合,每个元素包含两个值。
Map集合的每个元素的格式:key=value(键值对元素),Map集合也被称为键值对集合
Map集合的完整格式:{key1=value1, key2=value2, key3=value3, ...}
Map集合的体系:
Map<K , V>(接口,Map集合的祖宗类)
/ \
TreeMap<K , V> HashMap<K , V>(实现类,经典的,用的最多)
\
LinkedHashMap<K, V>(实现类)
Map集合的特点:
- Map 集合的特点都是由键决定的
- Map 集合的键是无序,不重复的,无索引的(Set)
- Map 集合的值无要求(List)
- Map 集合的键值对都可以为 null
- Map 集合后面重复的键对应元素会覆盖前面的元素
HashMap:元素按照键是无序,不重复,无索引,值不做要求
LinkedHashMap:元素按照键是有序,不重复,无索引,值不做要求
//经典代码 Map<String , Integer> maps = new HashMap<>(); maps.put("手机",1); System.out.println(maps);
常用API
Map 集合的常用 API
public V put(K key, V value)
:把指定的键与值添加到 Map 集合中,重复的键会覆盖前面的值元素public V remove(Object key)
:把指定的键对应的键值对元素在集合中删除,返回被删除元素的值public V get(Object key)
:根据指定的键,在 Map 集合中获取对应的值public Set<K> keySet()
:获取 Map 集合中所有的键,存储到 Set 集合中public Collection<V> values()
:获取全部值的集合,存储到 Collection 集合public Set<Map.Entry<K,V>> entrySet()
:获取Map集合中所有的键值对对象的集合public boolean containsKey(Object key)
:判断该集合中是否有此键
public class MapDemo { public static void main(String[] args) { Map<String , Integer> maps = new HashMap<>(); maps.put(.....); System.out.println(maps.isEmpty());//false Integer value = maps.get("....");//返回键值对象 Set<String> keys = maps.keySet();//获取Map集合中所有的键, //Map集合的键是无序不重复的,所以返回的是一个Set集合 Collection<Integer> values = maps.values(); //Map集合的值是不做要求的,可能重复,所以值要用Collection集合接收! } }
遍历方式
Map集合的遍历方式有:3种。
- “键找值”的方式遍历:先获取 Map 集合全部的键,再根据遍历键找值。
- “键值对”的方式遍历:难度较大,采用增强 for 或者迭代器
- JDK 1.8 开始之后的新技术:foreach,采用 Lambda表 达式
集合可以直接输出内容,因为底层重写了 toString() 方法
public static void main(String[] args){ Map<String , Integer> maps = new HashMap<>(); //(1)键找值 Set<String> keys = maps.keySet(); for(String key : keys) { System.out.println(key + "=" + maps.get(key)); } //Iterator<String> iterator = hm.keySet().iterator(); //(2)键值对 //(2.1)普通方式 Set<Map.Entry<String,Integer>> entries = maps.entrySet(); for (Map.Entry<String, Integer> entry : entries) { System.out.println(entry.getKey() + "=>" + entry.getValue()); } //(2.2)迭代器方式 Iterator<Map.Entry<String, Integer>> iterator = maps.entrySet().iterator(); while (iterator.hasNext()) { Map.Entry<String, Integer> entry = iterator.next(); System.out.println(entry.getKey() + "=" + entry.getValue()); } //(3) Lamda maps.forEach((k,v) -> { System.out.println(k + "==>" + v); }) }
HashMap
基本介绍
HashMap 基于哈希表的 Map 接口实现,是以 key-value 存储形式存在,主要用来存放键值对
特点:
- HashMap 的实现不是同步的,这意味着它不是线程安全的
- key 是唯一不重复的,底层的哈希表结构,依赖 hashCode 方法和 equals 方法保证键的唯一
- key、value 都可以为null,但是 key 位置只能是一个null
- HashMap 中的映射不是有序的,即存取是无序的
- key 要存储的是自定义对象,需要重写 hashCode 和 equals 方法,防止出现地址不同内容相同的 key
JDK7 对比 JDK8:
- 7 = 数组 + 链表,8 = 数组 + 链表 + 红黑树
- 7 中是头插法,多线程容易造成环,8 中是尾插法
- 7 的扩容是全部数据重新定位,8 中是位置不变或者当前位置 + 旧 size 大小来实现
- 7 是先判断是否要扩容再插入,8 中是先插入再看是否要扩容
底层数据结构:
-
哈希表(Hash table,也叫散列表),根据关键码值而直接访问的数据结构。通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度,这个映射函数叫做散列函数,存放记录的数组叫做散列表
-
JDK1.8 之前 HashMap 由 数组+链表 组成
- 数组是 HashMap 的主体
- 链表则是为了解决哈希冲突而存在的(拉链法解决冲突),拉链法就是头插法,两个对象调用的 hashCode 方法计算的哈希码值(键的哈希)一致导致计算的数组索引值相同
-
JDK1.8 以后 HashMap 由 数组+链表 +红黑树数据结构组成
- 解决哈希冲突时有了较大的变化
- 当链表长度超过(大于)阈值(或者红黑树的边界值,默认为 8)并且当前数组的长度大于等于 64 时,此索引位置上的所有数据改为红黑树存储
- 即使哈希函数取得再好,也很难达到元素百分百均匀分布。当 HashMap 中有大量的元素都存放到同一个桶中时,就相当于一个长的单链表,假如单链表有 n 个元素,遍历的时间复杂度是 O(n),所以 JDK1.8 中引入了 红黑树(查找时间复杂度为 O(logn))来优化这个问题,使得查找效率更高
参考视频: