1、Java有哪些集合
2、不同集合的应用场景分别是哪些
3、哪些实现类是线程安全的
4、为什么Java集合不能存放基本类型
5、集合的fail-fast和fail-safe是什么
Java集合概览Java通过Java Collections Framework(JCF)为开发者提供了一系列集合接口和实现,所谓集合,就是多个Java对象的聚集。
学习过数据结构的同学们对各类集合的定义肯定不陌生,Java通过提供一系列的内置数据结构实现,为开发者提高了开发的便利性,提升了程序的兼容性,降低了编程的复杂性。
图片出自https://www.pdai.tech/md/java/collection/java-collection-all.html
Java集合包含两个顶层接口:Collection和Map,Collection是主要保存对象的集合,Map是保存键值对的集合。
下面我们对两类集合的实现做简单介绍。
CollectionCollection是Jdk1.2版本引入的接口,用于描述保存对象的集合,它的扩展接口有List、Queue、Set。
ListList以列表形式顺序存取元素,保证元素的插入顺序和存储顺序一致。
实现 线程安全ArrayList 数组 否
LinkedList 双向链表 否
CopyOnWriteArrayList 数组 是,使用CopyOnWrite保证线程安全
Vector 数组 是,使用Synchronized保证线程安全
Stack 数组 是,继承Vector
Vector是Jdk1.0就引入的线程安全的列表实现,早于Collection接口设计,采用直接在方法上添加Synchronized来保证线程安全,Stack是继承Vector实现的栈结构,由于其线程安全的低效性,目前在实际环境均不再推荐使用。
QueueQueue是先进先出的结构,从队尾加入元素,队头弹出元素。其子接口Deque为双端队列,即两头都可以进出。
实现 线程安全ArrayDeque 循环数组 否
LinkedList 链表 否
PriorityQueue 堆 否
BlockingQueue BlockingQueue为阻塞队列的扩展接口 是
由于BlockingQueue略为复杂,更涉及到一些进阶应用场景,留待后续讲解。
SetSet是不重复元素集合,元素中不包含相同元素,且通常情况不保持元素插入顺序
实现 线程安全HashSet 哈希表 否,基于HashMap实现
TreeSet 红黑树 否,基于TreeMap实现
LinkedHashSet 哈希表+链表 否,基于LinkedHashMap实现
CopyOnWriteArraySet 数组 是,CopyOnWrite保证
ConcurrentSkipListSet 跳表 是,基于ConcurrentSkipListMap实现
Map
Map用于存储<Key, Value>键值对。
实现 线程安全HashMap 哈希表+红黑树 否
TreeMap 红黑树 否
LinkedHashMap 哈希表+链表+红黑树 否
WeakHashMap 哈希表 否
ConcurrentHashMap 哈希表+红黑树 是,基于节点CAS和Synchronized实现
ConcurrentSkipListMap 跳表 是
为什么Java集合不能存放基本类型
Java在1.2版本引入JCF框架,Java范型是在1.5版本引入,因此在泛型引入之前集合默认以Object作为存储类型。
以List为例 List list = new ArrayList(); list.add(123); // 自动boxing list.add("123"); int num = (int) list.get(0); String str = (String) list.get(1);显而易见该方式存在缺陷,集合内可以放入任何以Object为基类的元素,而元素的获取方无法确定元素的具体类型,容易出现类型转换错误。在1.5版本引入范型以后,对集合接口进行规范,添加了范型参数,Java的泛型机制本质上还是将具体类型擦除为Object,因此泛型集合在初始化时,无法将参数指定为非Object派生的基本类型。
什么是fail-fast和fail-safe List<String> list = new ArrayList(); list.add("123"); list.add("456"); //(1) throw ConcurrentModificationException for (String s : list) { list.remove(s); } //(2) 正常移除 Iterator<String> it = list.iterator(); while (it.hasNext()) { it.next(); it.remove(); } //(3) throw ConcurrentModificationException new Thread(() -> { for (String s : list) { System.out.println(s); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException ignore) { } } }).start(); new Thread(() -> {list.add("789");}).start();