Java面试基础篇之集合
文章目录
- 你知道的集合都有哪些?
- 哪些集合是线程安全的?
- Collection
- 集合类和数组有什么不同?
- Collection和Collections有什么区别?
- 如何确保一个集合不能被修改?
- List和Set的区别?
- List集合
- ArrayList和LinkedList的区别?
- ArrayList动态扩容机制?
- List和数组之间可以转换吗?
- 讲一讲Vector集合?
- ArrayList和Vector的区别?
- 讲一讲Stack集合?
- Set集合
- 讲一讲HashSet?
- 讲一讲LinkedHashSet?
- 讲一讲TreeSet?
- Queue队列
- 讲一讲Queue?
- 说一下Queue中remove()和poll()的区别?
- Map集合
- 什么是HashMap?
- 说一说HashMap的底层数据结构?
- 为什么要改成"数组+链表+红黑树"?
- 为什么链表转红黑树的阈值是8?
- 那么转回链表的阈值用的是6怎么不复用8?
- HashMap的扩容机制
- 负载因子为什么是0.75不是别的?
- 简单说一下TreeMap?
- 简单说一下LinkedHashMap?
- ConcurrentHashMap和HashMap的区别?
- ConcurrentHashMap如何保证线程安全的?
- CAS是什么?
- 说一说Hashtable?
- Hashtable和HashMap有什么区别?
- Iterator迭代器
- Iterator迭代器是什么?
- 说一说ListIterator迭代器?
- Iterator和ListIterator有什么区别?
- 关于forEach?
你知道的集合都有哪些?
List
ArrayList
LinkedList
Vector
Stack
Set
HashSet
LinkedHashSet
TreeSet
Map
HashMap
LinkedHashMap
TreeMap
ConcurrentHashMap
Hashtable
哪些集合是线程安全的?
Vector
Stack
Hashtable
ConcurrentHashMap
Collection
集合类和数组有什么不同?
- 数组长度是固定的,而集合类的长度是可变的,数组用来存放基本数据类型,集合用来存放对象
Collection和Collections有什么区别?
Collection
是一个集合接口,它提供了对集合对象进行基本操作的通用接口方法,List
和Set
是它的子类Collections
是一个包装类,包含了很多静态方法,不能被实例化,属于一个工具类,提供一些工具方法,比如:sort(list)
排序等
如何确保一个集合不能被修改?
- 可以使用
Collections.unmodifiableCollection(Collection c)
方法来创建一个只读集合 - 对集合进行任何修改操作都会抛出
UnsupportedOperationException
异常
List<String> list = new ArrayList<>();
list.add("x");
Collection<String> cList = Collections.unmodifiableCollection(list);
cList.add("y"); // 运行时此行报错
System.out.println(list.size());
List和Set的区别?
List
接口实例储存的是有序的,可以重复的元素,可以通过索引直接操作元素Set
接口实例储存的是无序的,不可以重复的元素,不能通过索引获取元素,元素的唯一性靠储存的元素类型是否重写hashCode()
和equals()
方法来保证,如果没有重写这两个方法,则无法保证元素的唯一性
List集合
ArrayList和LinkedList的区别?
ArrayList
的底层是由动态数组的数据结构实现,查询速度快,增删速度慢LinkedList
的底层实现基于双向链表,查询慢,增删速度快
ArrayList动态扩容机制?
- 在JDK1.8中,先创建时,数组的初始容量为0
- 当添加第一个元素时,真正的分配容量,默认分配为10
- 当容量不足时(容量为
size
,添加第size+1
个元素时),先判断按照1.5倍(位运算)的比例扩容能否满足最低容量要求,能满足则按照1.5倍扩容,不能满足则以最低容量要求进行扩容
List和数组之间可以转换吗?
- 数组转
List
: 使用Arrays.asList(array)
进行转换 List
转数组: 使用List
自带的toArray()
方法
讲一讲Vector集合?
Vector
集合的内部实现类似于ArrayList
,Vector
也是基于一个容量能够动态增长的数组实现,但是Vector
的扩容机制是2倍扩容,很多方法都加入同步语句(源码方法中有synchronized
),所以线程相对安全
ArrayList和Vector的区别?
ArrayList
是线程不安全的,Vector
是线程相对安全的- 因为
Vector
中加入同步语句,所以效率性能不如ArrayList
Vector
的扩容机以是2倍扩容,而ArrayList
是以1.5倍扩容的
讲一讲Stack集合?
Stack
集合继承了Vector
集合,所以底层也是由数组实现,是线程安全的- 以一种"后进先出"(LIFO)的线性数据结构来储存元素,是一种特殊的线性表
- 元素的添加和删除操作只能在表的一端进行,即栈顶,对元素的访问加以限制,仅仅提供对栈顶元素的访问操作
- 对栈顶元素的操作实际上是对数组尾部元素的操作
Set集合
讲一讲HashSet?
HashSet
底层是基于HashMap
实现的,所以底层基本是直接调用HashMap
的相关方法完成,HashSet
保存无序不重复的元素,线程不安全
讲一讲LinkedHashSet?
LinkedHashSet
继承于HashSet
,但是它的底层并不是以HashMap
实现,而是以LinkedHashMap
实现,通过在HashSet
的构造方法中传入一个参数true,来引用LinkedHashMap
,以下为源码:
HashSet(int initialCapacity, float loadFactor, boolean dummy) {map = new LinkedHashMap<>(initialCapacity, loadFactor);
}
讲一讲TreeSet?
TreeSet
底层是由TreeMap
实现的,添加的数据存入的Map
的key
位置,而value
则是固定的PRESENT
(Object
)TreeSet
的元素是有序且不重复的,向TreeSet
中存放的对象必须实现Comparable
,线程不安全
Queue队列
讲一讲Queue?
Queue
继承了Collection
是一种特殊的线性表,遵循的是"先进先出"(FIFO)的的基本原则- 一般来说,它只允许在表的前端进行删除操作,在表达后端进行插入操作,但是某些队列允许在任何地方插入删除,比如说常用的
LinkedList
集合,实现了Queue
接口 - 队列主要分为阻塞和非阻塞,有界和无界、单向链表和双向链表之分
说一下Queue中remove()和poll()的区别?
poll()
移除并返回队列头部的元素,如果队列为空,则返回nullremove()
移除并返回队列头部的元素,如果队列为空,则抛出NoSuchElementException异常
Map集合
什么是HashMap?
HashMap
: 哈希表,也称为散列表是一种插入,查找,删除操作性能很高的数据结构,保存key-value
的映射关系的集合,线程不安全
说一说HashMap的底层数据结构?
在JDK1.8之前是HashMap
是采用数组+链表实现的,JDK1.8之后HashMap
的底层是通过数组+链表+红黑树来实现的
HashMap
的主干是一个Entry
数组,每一个Entry
包含一个key-value
键值对- 在存入数据时,会先计算key的
hashCode
来确定在数组上的储存位置,这个位置通常称为hash
桶 - 两个不同元素计算出的
hashCode
可能相同,这种情况称为**hash
冲突(hash
碰撞),这时当元素准备存入hash
桶时,发现已经被其他元素占用**,这时HasMap
采用链地址的方法,就是将元素通过链表的结构储存 - 如果定位到的数组包含链表,存入前先遍历链表,存在即覆盖,否则新增
- 当数组长度大于64,链表长度超过8,链表结构会更变为红黑树
- 对于移除,当链表长度小于等于6时,该位置的节点从红黑树转换成链表
- 由于查询时,定位在链表结构的数据时,仍然需要遍历链表
HashMap
中的链表出现越少,性能越好
为什么要改成"数组+链表+红黑树"?
- 主要是为了提升
hash
冲突严重链表过长的查询性能
为什么链表转红黑树的阈值是8?
HashMap
在设计时也面临空间与时间的权衡,红黑树的节点大小约为链表的两倍,如果阈值设置太小,红黑树的查询性能得不到体现,浪费空间- 根据计算链表中节点的个数到达8时,红黑树的性能才会开始展现
那么转回链表的阈值用的是6怎么不复用8?
- 如果节点数在8之间来回徘徊,就会频繁的更改数据结构,对性能造成损耗
HashMap的扩容机制
- 不指明初始大小时初始容量是16,容量必须是2的N次方,当数组中的元素的个数达到扩容阈值
threshold
,触发两倍扩容 - 扩容阈值 = 容量 * 负载因子(默认是0.75),可以理解为总容量的75%
负载因子为什么是0.75不是别的?
一样的思路,空间和时间的权衡,0.75是比较合适的值
负载因子太小,会导致表中的数据还很少就开始扩容,浪费空间
负载因子太大,可能会导致表中的链表长度变长,影响查询效率
简单说一下TreeMap?
TreeMap
底层通过红黑树实现,存入的元素默认情况下通过key值的自然顺序排序,线程不安全
简单说一下LinkedHashMap?
LinkedHashMap
继承自HashMap
,可以说LinkedHashMap
=HashMap
+ 双向链表,保证了插入的Entry
中的顺序,默认按照插入顺序排序,线程不安全
ConcurrentHashMap和HashMap的区别?
ConcurrentHashMap
是线程安全的HashMap
是线程非安全的
ConcurrentHashMap如何保证线程安全的?
- 在JDK1.7版本,使用了分段锁思想,采用Segment字段,解决了
HashTable
锁范围广的问题,将数据分段储存,给每一段数据加锁
- 在JDK1.8版本,采用数组中的元素作为锁,从而实现对头节点进行加锁,并发控制使用synchronized和CAS来操作
CAS是什么?
Compare-And-Swap
比较并替换,CAS
需要3个操作数: 内存地址V,旧的预期值A,即将要更变的新目标值BCAS
指令执行时,仅当内存地址V和预期值A相等时,将内存地址V的值更改为B,否则什么都不做CAS
是乐观锁技术,当多个线程尝试使用CAS
同时更新同一个变量时,只有一个线程能够更新,其他的线程都失败,失败的线程不会被挂起,而是被告知这次竞争中失败,并不断再次尝试- 详见Java面试基础篇之多线程
说一说Hashtable?
Hashtable
的底层和HashMap
非常类似,但是它是线程安全的,通过源码可以看到它的主要方法加上了synchronized
Hashtable和HashMap有什么区别?
Hashtable
是线程安全的,HashMap
是线程非安全的Hashtable
的锁范围非常大,代价很高,效率性能低Hashtable
的默认初始容量是11,扩容机制是2倍+1key
和value
都不允许为null
,如果为null
会抛出异常
Iterator迭代器
Iterator迭代器是什么?
Iterator
不是集合,是一个接口,可以遍历集合的对象,为各种容器提供了公共的操作接口,隔离对容器的遍历操作和底层实现,从而解耦,只能单向遍历(向后遍历)也就是说,当前遍历的集合元素被增删时(迭代器调用
remove
方法除外),会抛出ConcurrentModificationException
(并发修改异常)迭代器的的核心方法:
next()
会返回迭代器的下一个元素,并且更新迭代器指针的位置hasNext()
用于检测集合中是否还有元素remove()
将迭代器返回的元素删除
List<String> coll = new ArrayList<>();coll.add("李冰冰");coll.add("范冰冰");coll.add("高圆圆");coll.add("陈圆圆");Iterator<String> it = coll.iterator();while (it.hasNext()) {String s = it.next();System.out.println(s);coll.add("章子怡");// 报异常coll.remove(s);// 报异常it.remove();}System.out.println("=====================" + coll);
说一说ListIterator迭代器?
ListIterator
继承于Iterator
接口,只能用于List集合的访问- 比起
Iterator
来说,ListIterator
对集合的遍历更加灵活,可以双向遍历(向前/向后遍历)
Iterator和ListIterator有什么区别?
ListIterator
的功能更加强大
Iterator
只能单向遍历,ListIterator
可以双向遍历ListIterator
可以使用add()
在List中添加元素,Iterator
不行ListIterator
可以用nextIndex()
和previousIndex()
定位当前索引位置,Iterator
不行ListIterator
可以通过set()
方法对对象进行修改,Iterator
不行
关于forEach?
forEach
增强for循环,是JDK1.5后出现的高级for循环,开业用来遍历数组和集合- 内部原理就是一个
Iterator
迭代器 - 使用
forEach
在遍历过程中不能对元素进行增删操作
Java面试基础篇之集合相关推荐
- Java面试基础篇之java基础语法之五:类和对象
目录 1. 类与对象的初步认知 2. 类和类的实例化 3. 类的成员 3.1 字段/属性/成员变量 3.2 方法 (method) 3.3 static 关键字 3.4 小结 4. 封装 4.1 pr ...
- Java面试基础篇之java基础语法之五:数组
目录 1. 数组基本用法 1.1 什么是数组 1.2 创建数组 1.3 数组的使用 2. 数组作为方法的参数 2.1 基本用法 2.2 理解引用类型(重点/难点) 2.3 认识 null 3. 数组作 ...
- Java面试基础篇——第九篇:BIO,NIO,AIO的区别
2019独角兽企业重金招聘Python工程师标准>>> 现在IO模型主要分三类:BIO(同步阻塞IO),NIO(同步非阻塞IO),AIO(). 先来看看BIO. 1. BIO 服务端 ...
- 2021Java面试-基础篇
文章目录 前言 一: Java概述 1.何为编程 2.JDK1.5之后的三大版本 3.JVM,JRE和JDK的关系 4.什么是跨平台?原理是什么 5.Java语言有哪些特点 6.什么是字节码?采用字节 ...
- java gui中文变方块_150道Java面试基础题(含答案)
1)Java 中能创建 volatile 数组吗? 能,Java 中可以创建 volatile 类型数组,不过只是一个指向数组的引用,而不是整个数组.我的意思是,如果改变引用指向的数组,将会受到 vo ...
- java面试基础题整理(二)
java面试基础题整理 文章目录 java面试基础题整理 前端技术(HTML.CSS.JS.JQuery等) 在js中怎么样验证数字? js中如何给string这个类型加方法? 谈谈js的定时器? 请 ...
- Java面试基础知识III
Java面试基础知识: 1.C++或Java中的异常处理机制的简单原理和应用. 当JAVA 程序违反了JAVA的语义规则时,JAVA虚拟机就会将发生的错误表示为一个异常.违反语义规则包括2种情况.一种 ...
- java面试基础(三)
java面试基础(三) 十.设计模式 88.说一下你熟悉的设计模式? 89.简单工厂和抽象工厂有什么区别? 90.为什么要使用 spring? 91.解释一下什么是 aop? 92.解释一下什么是 i ...
- java实现linkstring,【JAVA SE基础篇】32.String类入门
[JAVA SE基础篇]32.String类入门 1.字符串 1.String类又称作不可变字符序列 2.String位于java.lang包中,java程序默认导入java.lang包下所有的类 3 ...
最新文章
- 查看mongodb数据路径_【数据库】mongodb数据库安装
- 深入浅出的讲解傅里叶变换(完整)
- C++11 constexpr使用
- POJ 2385 Apple Catching
- python定义函数prime判断是否是素数_用自定义函数判断素数 用C语言编写自定义函数prime(int x),判断x是否为素数?...
- Java 1.7 ThreadPoolExecutor源码解析
- Element 2.13.0 发布,基于 Vue 的桌面端组件库
- strnpy函数的用法
- Linux上像windows的FinalData的修復工具
- 网页端epub阅读器你试过吗?这些阅读器竟然这么好用,书迷必看
- Irrlicht引擎源码剖析——第十三天
- linux 中文 文件名乱码,中文文件名乱码问题
- Web前端热门框架大全
- FastDDS(9)Security安全性
- Halcon生成标定描述文件
- SQL练习:表妹不在,没人帮我查表,只好自己来了
- RTCP Inactivity导致掉话
- 一个35岁男人的自学编程之路
- 刘振飞:躲在镜子背后听用户反馈
- 权限系统表 | 全方位认识 mysql 系统库(一)