Java集合个人笔记整理

在这里插入图片描述

总体概括

-Java容器分为Collection和Map两个大类
-Collection接口的子接口有:List、Set、Queue接口,Map不是Collection子接口
-Map/Collection/Queue接口是所有集合框架的父接口
-List接口实现类:ArrayList/LinkedList/Vector/CopyOnWriteArrayList/Stack
-Set接口实现类:HashSet/TreeSet/LinkedHashSet
-Map接口实现类:HashMap/LinkedHashMap/TreeMap/ConcurrentHashMap/HashTable/Properties

List

ArrayList

-ArrayList底层数据结构是Object数组。
-ArrayList线程不安全。
-ArrayList有序可重复。
-ArrayList随机访问效率高,ArrayList 实现了 RandomAccess 接口,因此查 找的时候非常快。
-ArrayList尾部添加删除时间复杂度O(1),指定位置添加和删除需要移动数组,时间复杂度O(n-1),适合顺序添加。
-ArrayList默认大小是10个元素,扩容后新容量为旧容量的1.5倍。
-ArrayList支持序列化。

LinkedList

-LinkedList底层使用的是双向链表数据结构(JDK1.6之前为循环链表,JDK1.7取消了循环)
-LinkedList线程不安全
-LinkedList有序可重复
-LinkedList适合插入和删除时间复杂度O(1),指定位置插入和删除需要移动位置时间复杂度O((n))
-LinkedList不支持高效的随机元素访问
-LinkedList采用的是尾插法
-空间消耗别 ArrayList 多

Vector

-Vector底层数据结构是Object数组
-Vector线程安全
-有序可重复
-随机访问效率高
-尾部添加删除时间复杂度O(1),指定位置添加和删除需要移动数组,时间复杂度O(n-1)
-Vector默认初始化容量是10,扩容为原来的2倍
-Vector不支持序列化

CopyOnWriteArrayList

-是一个线程安全的ArrayList,内部使用了重入锁(ReetrantLock)使用System.arraycopy()方法实现写时复制,写删改操作加锁,而读无锁
-底层数据结构是volatile修饰的Object数组
-适合读多写少的场景使用
-初始化容量是1
-有序可重复
-随机访问效率高
-尾部添加删除时间复杂度O(1),指定位置添加和删除需要移动数组,时间复杂度O(n-1)

Stack

-底层数据结构是Object数组,继承自Vector
-线程安全
-先进后出

Set

HashSet

-底层是HashMap,key是值,value是Object静态常量
-无序不可重复
-非线程安全
-无参的构造方法,默认初始容量是16,加载因子是0.75
-通过HashCode和equals判断相等
-迭代器,增强for循环遍历
-集合元素可以是null,但只能放入一个null

TreeSet(有序唯一)

-底层通过treeMap(红黑树)实现
-有序默认自然升须排序
-不可重复
-线程不安全
-集合元素不可以为null

LinkedHashSet

-LinkedHashSet底层实际上是一个LinkedHashMap(数组+双向链表)
-有序不可重复
-非线程安全
-集合元素不可以为null
-初始化容量16,负载因子是0.75

CopyOnWriteArraySet

-底层是通过CopyOnWriteArrayList实现的,也是动态数组结构
-线程安全
-无序不可重复
-适合读多写少

Map

HashMap

-底层由数组+链表+红黑树(jdk1.8增加)实现
-初始长度是16,加载因子是0.75
-HashMap链表转红黑树的条件是:链表长度大于8,数组容量大于64,如果数组不大于64会先扩容
-HashMap允许空的key-value键值对
-每次扩容为原来的2倍,将原集合的元素重新映射到新集合中

ConcurrentHashMap

-线程安全
-jdk1.7中的实现是引入了段的概念,把集合中的数据分成若干个段,每个段其实就是一个小的HashTable,给段进行加锁
-jdk1.8利用CAS+Synchronized来实现

LinkedHashMap

-LinkedHashMap是HashMap+LinkedList(数组+双向链表)的实现。
-key,value允许为空、key重复会覆盖,value允许重复、有序、非线程安全。

TreeMap(有序)

-TreeMap底层是红黑树实现的,红黑树结构天然支持排序,默认情况下通过key值的自然顺序进行排序
-key不能为null,单允许多个value为null
-线程不安全

HashTable

-Hashtable也是一个哈希散列表,Hashtable继承于Dictionary
-HashTable不允许空的key和value值
-线程安全
-HashTable的put和get增加了synchronized锁性能较差
-初始容量是11,扩容为原来的2n+1

ThreadLocal

1.每个Thread都有一个属于自己的ThreadLocalMap,这个ThreadLocalMap是ThreadLocal的一个内部类,类似于一个
HashMap集合
2.每次存取值都是通过ThreadLocalMap存取,key值为ThreadLocal实例,value是需要存放的值
ThreadLocal中的嵌套内部类ThreadLocalMap,这个类本质上是一个map,和HashMap之类的实现相似,依然是key-
value的形式,其中有一个内部类Entry,其中key可以看做是ThreadLocal实例,但是其本质是持有ThreadLocal实例的
弱引用。而线程本身Tread中会有threadLocals这个局部变量,这个局部变量就是ThreadLocalMap的实例存放数据是需
要先初始化这个变量每次保存时都是以一个ThreadLocal实例作为key值,存放的数据作为value值进行存放。一个
ThreadLocal只能存放一种指定的类型的数据。其所有功能都是通过ThreadLocalMap这个内部类实现的。

哪些集合类是线程安全的?

vector:就比arraylist多了个同步化机制(线程安全),因为效率较低,现在已 经不太建议使用。
在web应用中,特别是前台页面,往往效率(页面响应速度)是优 先考虑的。
statck:堆栈类,先进后出。
hashtable:就比hashmap多了个线程安全。
enumeration:枚举,相当于迭代器。

Java集合的快速失败机制 “fail-fast”?

是java集合的一种错误检测机制,当多个线程对集合进行结构上的改变的操作 时,有可能会产生 fail-fast 机制。
例如: 假设存在两个线程(线程1、线程2),线程1通过Iterator在遍历集合A中 的元素,在某个时候线程2修改了集合A的结构(是结构上面的修改,而不是简 单的修改集合元素的内容),那么这个时候程序就会抛出ConcurrentModificationException 异常,从而产生fail-fast机制。
原因: 迭代器在遍历时直接访问集合中的内容,并且在遍历过程中使用一个 modCount 变量。集合在被遍历期间如果内容发生变化,就会改变modCount 的值。每当迭代器使用hashNext()/next()遍历下一个元素之前,都会检测 modCount变量是否为expectedmodCount值,是的话就返回遍历;否则抛出异常,终止遍历。

解决办法:
1.在遍历过程中,所有涉及到改变modCount值得地方全部加上 synchronized。
2.使用CopyOnWriteArrayList来替换ArrayList

怎么确保一个集合不能被修改?

可以使用 Collections. unmodifiableCollection(Collection c) 方法来创建一个 只读集合,这样改变集合的任何操作都会抛出 Java. lang. UnsupportedOperationException 异常。 示例代码如下:

List<String> list = new ArrayList<>();
list. add("x");
Collection<String> clist = Collections. unmodifiableCollection(list);
clist. add("y"); // 运行时此行报错
System. out. println(list. size());

迭代器 Iterator 是什么?

Iterator 接口提供遍历任何 Collection 的接口。我们可以从一个 Collection 中使用迭代器方法来获取迭代器实例。迭代器取代了 Java 集合框架中的 Enumeration,迭代器允许调用者在迭代过程中移除元素。

Iterator 怎么使用?有什么特点?

Iterator 使用代码如下:

  List<String> list = new ArrayList
  Iterator<String> it = list. iterator();
  while(it. hasNext()){
     String obj = it. next();
     System. out. println(obj);
}

Iterator 的特点是只能单向遍历,但是更加安全,因为它可以确保,在当前遍历的集合元素被更改的时候,就会抛出 ConcurrentModificationException 异常。

如何边遍历边移除Collection中的元素?

边遍历边修改 Collection 的唯一正确方式是使用 Iterator.remove() 方法,如下:

  Iterator<Integer> it = list.iterator();
  while(it.hasNext()){
*// do something*
  it.remove();
 }

一种 常见的错误代码如下:

for(Integer i : list){
  list.remove(i)
}

运行以上错误代码会报 ConcurrentModificationException 异常。这是因为当使用 foreach(for(Integeri : list)) 语句时,会自动生成一个iterator 来遍历该 list,但同时该 list 正在被 Iterator.remove() 修改。
Java 一般不允许一个线程在遍历 Collection 时另一个线程修改它。

Iterator 和 ListIterator 有什么区别?

  • Iterator 可以遍历 Set 和 List 集合,而 ListIterator 只能遍历 List。
  • Iterator 只能单向遍历,而 ListIterator 可以双向遍历(向前/后遍历)。
  • ListIterator 实现 Iterator 接口,然后添加了一些额外的功能,比如添加一个元 素、替换一个元素、获取前面或后面元素的索引位置。

遍历一个 List 有哪些不同的方式?每种方法的实现原理是什 么?Java 中 List 遍历的最佳实践是什么?

遍历方式有以下几种:

  • for 循环遍历,基于计数器。在集合外部维护一个计数器,然后依次读 取每一个位置的元素,当读取到后一个元素后停止。
  • 迭代器遍历,Iterator。Iterator 是面向对象的一个设计模式,目的是屏 蔽不同数据集合的特点,统一遍历集合的接口。Java 在 Collections 中支 持了 Iterator 模式。
  • foreach 循环遍历。foreach 内部也是采用了 Iterator 的方式实现,使 用时不需要显式声明 Iterator 或计数器。优点是代码简洁,不易出错;缺 点是只能做简单的遍历,不能在遍历过程中操作数据集合,例如删除、替 换。

最佳实践: Java Collections 框架中提供了一个 RandomAccess 接口,用来标 记 List 实现是否支持Random Access。

  • 如果一个数据集合实现了该接口,就意味着它支持 Random Access,按位置读 取元素的平均时间复杂度为 O(1),如ArrayList。
  • 如果没有实现该接口,表示不支持 Random Access,如LinkedList。 推荐的做法就是,支持Random Access 的列表可用 for 循环遍历,否则建议 用 Iterator 或 foreach 遍历。

ArrayList 和 LinkedList 的区别是什么?

  • 数据结构实现:ArrayList 是动态数组的数据结构实现,而 LinkedList 是双向链表的数据结构实现。
  • 随机访问效率:ArrayList 比 LinkedList 在随机访问的时候效率要高,因为 LinkedList 是线性的数据存储方式,所以需要移动指针从前往后依次查找。
  • 增加和删除效率:在非首尾的增加和删除操作,LinkedList 要比 ArrayList 效率要高,因为ArrayList 增删操作要影响数组内的其他数据的下标。
  • 内存空间占用:LinkedList 比 ArrayList 更占内存,因为 LinkedList 的节点除了存储数据,还存储了两个引用,一个指向前一个元素,一个指向后一个元素。
  • 线程安全:ArrayList 和 LinkedList 都是不同步的,也就是不保证线程安全;

综合来说,在需要频繁读取集合中的元素时,更推荐使用 ArrayList,而在插入和删除操作较多时,更推荐使用 LinkedList。

补充:数据结构基础之双向链表
双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。

ArrayList 和 Vector 的区别是什么?

这两个类都实现了 List 接口(List 接口继承了 Collection 接口),他们都是有序集合。

线程安全:Vector 使用了 Synchronized 来实现线程同步,是线程安全的,而ArrayList 是非线程安全的。

性能: ArrayList 在性能方面要优于 Vector。
扩容: ArrayList 和 Vector 都会根据实际的需要动态的调整容量,只不过在
Vector 扩容每次会增加 1 倍,而 ArrayList 只会增加 50%。
Vector类的所有方法都是同步的。可以由两个线程安全地访问一个Vector对
象、但是一个线程访问Vector的话代码要在同步操作上耗费大量的时间。
Arraylist不是同步的,所以在不需要保证线程安全时时建议使用Arraylist。

插入数据时,ArrayList、LinkedList、Vector谁速度较快?阐述 ArrayList、Vector、LinkedList 的存储性能和特性?

ArrayList、LinkedList、Vector 底层的实现都是使用数组方式存储数据。数组

元素数大于实际存储的数据以便增加和插入元素,它们都允许直接按序号索引元素,但是插入元素要涉及数组元素移动等内存操作,所以索引数据快而插入数据慢。

Vector 中的方法由于加了 synchronized 修饰,因此 Vector是线程安全容器,但性能上较ArrayList差。

LinkedList 使用双向链表实现存储,按序号索引数据需要进行前向或后向遍历,但插入数据时只需要记录当前项的前后项即可,所以 LinkedList插入速度较快。

多线程场景下如何使用 ArrayList?

ArrayList 不是线程安全的,如果遇到多线程场景,可以通过 Collections 的synchronizedList 方法将其转换成线程安全的容器后再使用。例如像下面这样:

List<String> synchronizedList = Collections.synchronizedList(list);
  synchronizedList.add("aaa");
  synchronizedList.add("bbb");
  for (int i = 0; i < synchronizedList.size(); i++) {
    System.out.println(synchronizedList.get(i));
 }

为什么 ArrayList 的 elementData 加上 transient 修饰? ArrayList 中的数组定义如下:

private transient Object[] elementData;

再看一下 ArrayList 的定义:

public class ArrayList extends AbstractList implements List,
RandomAccess, Cloneable, java.io.Serializable

可以看到 ArrayList 实现了 Serializable 接口,这意味着 ArrayList 支持序列化。transient 的作用是说不希望 elementData 数组被序列化,重写了 writeObject 实现:
在这里插入图片描述
每次序列化时,先调用 defaultWriteObject() 方法序列化 ArrayList 中的非transient 元素,然后遍历elementData,只序列化已存入的元素,这样既加快了序列化的速度,又减小了序列化之后的文件大小。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Java面试资源概览 一、内容概览 本次分享的资源涵盖了Java面试的各个方面,从基础知识到高级技术,从数据库到框架应用,都做了深入的探讨和总结。具体内容包括: Java基础知识点:包括数据类型、面向对象特性、异常处理、集合框架等。 Java核心技术:如多线程、网络编程、序列化等都有详细的解释和示例。 常用框架:如Spring、MyBatis等框架的使用方法和内部原理都有涉及。 数据库相关:包括关系型数据库和非关系型数据库的使用,以及JDBC、MyBatis等与数据库交互的技术。 实战项目经验:分享了几个经典的Java项目,解析了项目的架构设计和核心技术点。 面试经验和技巧:整理了常见的Java面试问题,并给出了答题建议和技巧。 代码和项目实例:提供了多个Java项目的源代码,方便学习者参考和实践。 学习笔记和心得:记录了学习过程中的重点难点和心得体会,有助于学习者更好地理解和掌握知识。 二、适用人群 本资源适用于即将毕业或已经毕业,希望通过学习Java找到一份理想工作的同学。无论你是初学者还是有一定基础的开发者,都能从中获得启发和帮助。 三、使用建议 系统学习:建议学习者按照资源提供的顺序和内容,系统地学习和掌握Java的知识点。 实践为王:理论知识和实战经验相结合,通过实践来加深理解和记忆。 持续更新:由于Java技术和面试要求都在不断更新,建议学习者保持关注,随时更新自己的知识和技能。 交流与讨论:与同学或同行进行交流和讨论,分享学习心得和经验,共同进步。Java面试资源概览 一、内容概览 本次分享的资源涵盖了Java面试的各个方面,从基础知识到高级技术,从数据库到框架应用,都做了深入的探讨和总结。具体内容包括: Java基础知识点:包括数据类型、面向对象特性、异常处理、集合框架等。 Java核心技术:如多线程、网络编程、序列化等都有详细的解释和示例。 常用框架:如Spring、MyBatis等框架的使用方法和内部原理都有涉及。 数据库相关:包括关系型数据库和非关系型数据库的使用,以及JDBC、MyBatis等与数据库交互的技术。 实战项目经验:分享了几个经典的Java项目,解析了项目的架构设计和核心技术点。 面试经验和技巧:整理了常见的Java面试问题,并给出了答题建议和技巧。 代码和项目实例:提供了多个Java项目的源代码,方便学习者参考和实践。 学习笔记和心得:记录了学习过程中的重点难点和心得体会,有助于学习者更好地理解和掌握知识。 二、适用人群 本资源适用于即将毕业或已经毕业,希望通过学习Java找到一份理想工作的同学。无论你是初学者还是有一定基础的开发者,都能从中获得启发和帮助。 三、使用建议 系统学习:建议学习者按照资源提供的顺序和内容,系统地学习和掌握Java的知识点。 实践为王:理论知识和实战经验相结合,通过实践来加深理解和记忆。 持续更新:由于Java技术和面试要求都在不断更新,建议学习者保持关注,随时更新自己的知识和技能。 交流与讨论:与同学或同行进行交流和讨论,分享学习心得和经验,共同进步。Java面试资源概览 一、内容概览 本次分享的资源涵盖了Java面试的各个方面,从基础知识到高级技术,从数据库到框架应用,都做了深入的探讨和总结。具体内容包括: Java基础知识点:包括数据类型、面向对象特性、异常处理、集合框架等。 Java核心技术:如多线程、网络编程、序列化等都有详细的解释和示例。 常用框架:如Spring、MyBatis等框架的使用方法和内部原理都有涉及。 数据库相关:包括关系型数据库和非关系型数据库的使用,以及JDBC、MyBatis等与数据库交互的技术。 实战项目经验:分享了几个经典的Java项目,解析了项目的架构设计和核心技术点。 面试经验和技巧:整理了常见的Java面试问题,并给出了答题建议和技巧。 代码和项目实例:提供了多个Java项目的源代码,方便学习者参考和实践。 学习笔记和心得:记录了学习过程中的重点难点和心得体会,有助于学习者更好地理解和掌握知识。 二、适用人群 本资源适用于即将毕业或已经毕业,希望通过学习Java找到一份理想工作的同学。无论你是初学者还是有一定基础的开发者,都能从中获得启发和帮助。 三、使用建议 系统学习:建议学习者按照资源提供的顺序和内容,系统地学习和掌握Java的知识点。 实践为王:理论知识和实战经验相结合,通过实践来加深理解和记忆。 持续更新:由于Java技术和面试要求都在不断更新,建议学习者保持关注,随时更新自己的知识和技能。 交流与讨论:与同学或同行进行交流和讨论,分享学习心得和经验,共同进步。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

泡^泡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值