一文掌握常见常用Java集合框架
掌握常见常用Java集合框架
说到集合框架,下面这张图一定经常会看见
初看这副图,你可能会觉得眼花缭乱,问题不大,本文这就带你去了解这副图。
1.整体感知
从图中可以看出,集合框架主要分为两个类型,Collection和Map , Collection 是一个存储一系列单个对象的容器,Map 是一个图,可以存储 一系列键值对。Collection 有三个子接口 List, Set, Queue
所以集合框架有四种具体的类型:Map, List, Set, Queue
List代表了有序可重复集合,可直接根据元素的索引来访问;Set代表无序不可重复集合,只能根据元素本身来访问;Queue是队列集合;Map代表的是存储键值对(key-value)的集合,可根据元素的key来访问value。
2.顶层接口
Iterator Iterable ListIterator
先来看我们经常用到的 Iterator 接口 和它的子接口 ListIterator
Iterator 有三个主要方法
hasNext() : 检测集合是否还有下一个元素
next() : 返回迭代器的下一个元素,并更新迭代器的游标(类似指针)
remove() : 将迭代器返回的元素删除
下面来通过例子来观察一下
public static void main(String[] args) {List<Integer> list = new ArrayList<>();list.add(89);list.add(39);list.add(29);list.add(19);list.add(29);Iterator<Integer> it = list.iterator(); //获取迭代器while(it.hasNext()){Integer next = it.next();System.out.print(next + " ");}Iterator<Integer> it2 = list.iterator();while(it2.hasNext()){if(it2.next() < 30){it2.remove();}}System.out.println();Iterator<Integer> it3 = list.iterator(); //获取迭代器while(it3.hasNext()){Integer next = it3.next();System.out.print(next + " ");} }
输出结果为
89 39 29 19 29 89 39
下面解释一下运行的过程,新建一个ArrayList集合,往里面添加了5个元素,第一次获取迭代器,遍历了集合,第二次获取迭代器,把集合里小于30的数删除,第三次再获取迭代器,再次遍历集合,发现小于30的数都被删除掉了。
下面来看一下ListIterator 接口,具体可以参考:Java 集合中关于Iterator 和ListIterator的详解
(1)ListIterator有**add()方法,可以向List中添加对象,而Iterator不能
(2)ListIterator和Iterator都有hasNext()和next()方法,可以实现顺序向后遍历,但是ListIterator有hasPrevious()和previous()**方法,可以实现逆向(顺序向前)遍历。Iterator就不可以。
(3)ListIterator可以定位当前的索引位置,**nextIndex()和previousIndex()**可以实现。Iterator没有此功能。
(4)都可实现删除对象,但是ListIterator可以实现对象的修改,set()方法可以实现。Iierator仅能遍历,不能修改。
最后来看一下Iterable接口
public interface Iterable<T> {Iterator<T> iterator();/*** @since 1.8*/default void forEach(Consumer<? super T> action) {Objects.requireNonNull(action);for (T t : this) {action.accept(t);}}default Spliterator<T> spliterator() {return Spliterators.spliteratorUnknownSize(iterator(), 0);} }
可以看到其实里面也提供了Iterator接口,在JDK1.8之后,iterable提供foreach遍历,也就是我们经常用的增强for循环。但究其本质,增强for循环其实底层还是用迭代器遍历。
最后来小结一波
Iterator 是最常用的迭代器接口,主要提供了三个方法供我们去操作集合,hasNext(), next(), remove()。
ListIterator则可以称的上是Iterator的增强版,但它只可以对list集合操作,在Iterator的基础上,它还提供了add()方法,hasPrevious() 和 previous() 供我们后续遍历list集合,它还可以定位一个元素的索引和修改元素。
Iterable则提供了foreach遍历集合的方法。
3.Map集合
Map存储的是键值对<key, value> 形式的值, 每个key对应唯一一个value, 所以Map不可以有重复的key值,但存储重复的key值时,会将后来的 value 值覆盖掉原来的value值。也就是这个原因,作为key值得元素都必须重写hashcode()和equals()方法。
HashMap 和 HashTable
HashMap是最常用的一个实现类,当存入元素时,会将key的hashcode转化为数组的索引放入对应的数组位置,查找时以同样的方式查找。
HashTable一般都用不到了,操作方法和HashMap差不多,但性能比HashMap差,主要是底层实现导致的。HashTable有一个子类叫properties,是一个key和value都是String类型得Map,主要用于读取配置文件。
两者的区别:
- HashTable是线程安全的,HashMap是线程不安全的, HashTable底层实现的时候加了synchronized关键字。
- 底层实现时,HashTable是数组+链表,HashMap是数组+链表+红黑树, 具体是当链表长度大于8时会转为红黑树,因为这样查询效率会比原来快。
- HashMap可以用null作为key,而HashTable不可以
LinkedHashMap
LinkedHashMap是HashMap的子类,它内部有一条双向链表来维护键值对的次序,维护了Map的迭代顺序,与插入顺序一致,具体可以用来实现LRU缓存策略。
TreeMap
TreeMap有排序的功能,底层是数组+红黑树实现的,每一个键值对是一个树节点,默认按key值排序,因此key值必须实现Comparable接口。迭代的时候输出就是按照key值得默认顺序输出。
下面来例子演示一下
public static void main(String[] args) {Map<String, Integer> hashmap = new HashMap<>();hashmap.put("Messi",6);hashmap.put("Ronaldo",5);hashmap.put("Kaka",1);hashmap.put("Modric",1);hashmap.put("Lingard",100);System.out.println("用HashMap: ");Set<Map.Entry<String, Integer>> set1 = hashmap.entrySet();for(Map.Entry<String, Integer> s: set1){System.out.println(s.getKey() +" "+s.getValue());}Map<String, Integer> linkedHashMap = new LinkedHashMap<>();linkedHashMap.put("Messi",6);linkedHashMap.put("Ronaldo",5);linkedHashMap.put("Kaka",1);linkedHashMap.put("Modric",1);linkedHashMap.put("Lingard",100);System.out.println("用LinkedHashMap: ");Set<Map.Entry<String, Integer>> set2 = linkedHashMap.entrySet();for(Map.Entry<String, Integer> s: set2){System.out.println(s.getKey() +" "+s.getValue());}Map<String,Integer> treeMap = new TreeMap<>();treeMap.put("Messi",6);treeMap.put("Ronaldo",5);treeMap.put("Kaka",1);treeMap.put("Modric",1);treeMap.put("Lingard",100);System.out.println("用TreeMap: ");Set<Map.Entry<String, Integer>> set3 = treeMap.entrySet();for(Map.Entry<String, Integer> s: set3) {System.out.println(s.getKey() + " " + s.getValue());} }
用HashMap: Ronaldo 5 Lingard 100 Modric 1 Messi 6 Kaka 1 用LinkedHashMap: Messi 6 Ronaldo 5 Kaka 1 Modric 1 Lingard 100 用TreeMap: Kaka 1 Lingard 100 Messi 6 Modric 1 Ronaldo 5
用HashMap会使遍历得时候变得无序,每次遍历得时候可能都会不一样,用LinkedHashMap
则严格按照添加顺序输出, 用TreeMap时则会将key值排序在输出。
4.Set集合
Set集合就是存储一系列不重复得元素,和Map有点像,就是少了value。
Set集合和基本上差不多,有几个具体得实现类,
HashSet,是基于HashMap 实现的,
** LinkedHashSet ,是基于LinkedHashMap实现的, **
TreeSet,是基于TreeMap实现的
操作除了没了value值,和Map差不多,存储的元素都要重写hashcode()和equals()方法。
5.List集合
常见的实现有ArrayList, LinkedList, Vector, Stack,
先说一下Vector和Stack, Stack是vector 的子类,它们都是线程安全的,也正是因为这一点,使得它们现在已经过时了。
ArrayList 继承了 AbstractList ,并实现了 List 接口。
ArrayList 新建时默认容量为10,如果快达到了容量,就会有扩容机制将容量扩大到原来的1.5倍,所以如果我们创建ArrayList时知道要存储大小时最好指定一下大小,避免不断扩容而增大开销
LinkedList类似于 ArrayList,底层是用链表实现的,并实现了List, Deque, Cloneable, Serializable
接口,实现了Deque接口,说明Deque可以当作双端队列来使用,也就是说,既可以当作“栈”使用,又可以当作队列使用。
你需要通过循环迭代来访问列表中的某些元素。
需要频繁的在列表开头、中间、末尾等位置进行添加和删除元素操作。
6.Queue集合
主要分为单向队列和双端队列,双端队列就是实现Deque接口,最常见的就是上面所说的LinkedList, 单向队列主要介绍优先队列PriorityQueue。
- 下面先来看JDK为我们提供的双端队列方法
细心的朋友可能会发现,API为每种操作都提供两种方法,那么它们有什么不同呢,调用不同方法操作失败时,结果也会不同。
失败结果 | 添加 | 删除 | 查找 |
---|---|---|---|
抛出异常 | add() | remove() | get() |
False | offer() | poll() | peek() |
实现双端队列的除了LinkedList, 还有ArrayDeque, 两者的区别和LinkedList和ArrayList的区别有点像,都是一个底层是链表,一个是数组。用的不多
最后讲一下单向队列的PriorityQueue
PriorityQueue是基于优先堆实现的,优先队列,顾名思义它可以根据优先级来进行排序
要求添加的元素实现Comparable接口,并不可以存NULL值
下面来个例子演示一下
先定义了一个Player类,实现Comparable接口,并重写了CompareTo方法
public static void main(String[] args) {Queue<Player> players = new PriorityQueue<>();Player p1 = new Player("Ronaldo", 93);Player p2 = new Player("Messi",94);Player p3 = new Player("Neymar",92);Player p4 = new Player("lewandovsiki",91);Player p5 = new Player("Lingard",100);players.add(p1);players.add(p2);players.add(p3);players.add(p4);players.add(p5);while (!players.isEmpty()){Player p = players.poll();System.out.println(p);} }
Player{name='Lingard', ability=100}
Player{name='Messi', ability=94}
Player{name='Ronaldo', ability=93}
Player{name='Neymar', ability=92}
Player{name='lewandovsiki', ability=91}
会发现输出顺序和ability有关,这是因为内部已经根据CompareTo方法排好序了,也就是根据ability为优先级了。
最后献上一个表格来总结一下
实现类 | 增删复杂度 | 查复杂度 | 底层数据结构 | 线程安全 |
---|---|---|---|---|
Vector | O(N) | O(1) | 数组 | 是(过时) |
ArrayList | O(N) | O(1) | 数组 | 否 |
LinkedList | O(1) | O(N) | 双向链表 | 否 |
HashSet | O(1) | O(1) | 数组+链表+红黑树 | 否 |
TreeSet | O(logN) | O(logN) | 红黑树 | 否 |
LinkedHashSet | O(1) | O(1)~O(N) | 数组 + 链表 + 红黑树 | 否 |
ArrayDeque | O(N) | O(1) | 数组 | 否 |
PriorityQueue | O(logN) | O(logN) | 堆(数组实现) | 否 |
HashTable | O(1) / O(N) | O(1) / O(N) | 数组+链表 | 是(过时) |
HashMap | O(1) ~ O(N) | O(1) ~ O(N) | 数组+链表+红黑树 | 否 |
TreeMap | O(logN) | O(logN) | 数组+红黑树 | 否 |
HashTable | O(1) / O(N) | O(1) / O(N) | 数组+链表 | 是(过时) |
HashMap | O(1) ~ O(N) | O(1) ~ O(N) | 数组+链表+红黑树 | 否 |
TreeMap | O(logN) | O(logN) | 数组+红黑树 | 否 |
一文掌握常见常用Java集合框架相关推荐
- -1-3 java集合框架基础 java集合体系结构 Collection 常用java集合框架 如何选择集合 迭代器 泛型 通配符概念 Properties 集合 迭代器...
集合又称之为容器存储对象的一种方式 •数组虽然也可以存储对象,但长度是固定的:显然需要可变长度的容器 集合和数组的区别? A:长度区别 ...
- Java集合框架之四大接口、常用实现类,java基础面试笔试题
我总结出了很多互联网公司的面试题及答案,并整理成了文档,以及各种学习的进阶学习资料,免费分享给大家. 扫描二维码或搜索下图红色VX号,加VX好友,拉你进[程序员面试学习交流群]免费领取.也欢迎各位一起 ...
- java arraylist排序_一文读懂Java集合框架
欢迎关注微信公众号:深入浅出Java源码 概念 Java集合框架为程序员提供了预先包装的数据结构和算法来操纵他们.集合框架被设计成要满足以下几个目标. 该框架必须是高性能的.基本集合(动态数组,链表, ...
- 容器(一)剖析面试最常见问题之 Java 集合框架
转载自https://github.com/Snailclimb/JavaGuide/blob/master/docs/java/collection/Java%E9%9B%86%E5%90%88%E ...
- java list有序还是无序_牛批!2w字的Java集合框架面试题精华集(2020最新版),赶紧收藏。...
一个多月前,作者和一些小伙伴决定做一系列的 Java 知识点常见重要问题的小册,方便用来夯实基础!小册的标准就一个,那就是:取精华,取重点.每一本小册,我们都会充分关注我们所总结的知识点是否达到这个标 ...
- Java集合框架使用总结
Java集合框架使用总结 前言: 本文是对Java集合框架做了一个概括性的解说,目的是对Java集合框架体系有个总体认识,如果你想学习具体的接口和类的使用方法,请参看JavaAPI文档. 一.概述 数 ...
- 「Java面试题精华集」1w字的Java集合框架篇(2022最新版)附PDF版
昨天晚上终于把 Java 集合框架部分的的知识点肝完了,转换成 PDF 一共 25 页,后台回复:"面试突击" 即可免费获取下载地址(同样提供了夜间阅读版本). 集合概述 Java ...
- 【Java集合框架】ArrayList类方法简明解析(举例说明)
本文目录 1.API与Java集合框架 2.ArrayList类方法解析 2.1 add() 2.2 addAll() 2.3 clear() 2.4 clone() 2.5 contains() 2 ...
- Java集合框架之fastutil
fastutil扩展了 Java集合框架,通过提供特定类型的map.set.list和queue,以及小内存占用.快速访问和插入:也提供大(64位)array.set 和 list,以及快速.实用的 ...
最新文章
- system.err android.os.NetworkOnmainThreadException 错误解决办法
- c语言long long类型赋值
- linux 清理指定大小的文件
- GoogleAppEngine是什么?
- 02 socketserver客户端
- ANSIBLE---变量
- redis配置文件conf详解
- ftp服务器vsftpd配置文件,vsftpd配置文件详解及ftp服务器搭建
- Swagger注解生成插件
- 三极管原理及特性分析
- 点量云流化技术在云游戏和虚拟仿真教学中有啥优势?
- 【最大流,最大匹配,最大独立集】2018.6.18 【2018提高组】模拟C组 T3 沙耶的玩偶
- mysql表误删回复_MySQL数据库误删恢复
- MCE | “神药”二甲双胍后,糖尿病药物研究谁将是下一个顶流?
- 将git项目提交到其他的git仓库
- 担心基站高辐射?快来看5G建设电磁辐射科普宣传片
- 录取为2021年同济大学秋季博士研究生(电子与信息工程学院计算机科学与技术)
- git clone 拉取远程仓库
- 哈佛女校长给2008年本科毕业生的演讲
- 计算机联锁仿真论文,计算机联锁系统仿真平台的研究