Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
qq_21481385
JavaGuide
提交
5fdb3f86
J
JavaGuide
项目概览
qq_21481385
/
JavaGuide
与 Fork 源项目一致
从无法访问的项目Fork
通知
1
Star
1
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
J
JavaGuide
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
提交
5fdb3f86
编写于
11月 27, 2020
作者:
G
guide
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
[fix]图片地址出错
上级
f2c3a98c
变更
1
隐藏空白更改
内联
并排
Showing
1 changed file
with
1 addition
and
228 deletion
+1
-228
docs/java/collection/Java集合框架常见面试题.md
docs/java/collection/Java集合框架常见面试题.md
+1
-228
未找到文件。
docs/java/collection/Java集合框架常见面试题.md
浏览文件 @
5fdb3f86
...
...
@@ -10,11 +10,6 @@
-
[
1.1.3.3. Map
](
#1133-map
)
-
[
1.1.4. 如何选用集合?
](
#114-如何选用集合
)
-
[
1.1.5. 为什么要使用集合?
](
#115-为什么要使用集合
)
-
[
1.1.6. Iterator 迭代器
](
#116-iterator-迭代器
)
-
[
1.1.6.1. 迭代器 Iterator 是什么?
](
#1161-迭代器-iterator-是什么
)
-
[
1.1.6.2. 迭代器 Iterator 有啥用?
](
#1162-迭代器-iterator-有啥用
)
-
[
1.1.6.3. 如何使用?
](
#1163-如何使用
)
-
[
1.1.7. 有哪些集合是线程不安全的?怎么解决呢?
](
#117-有哪些集合是线程不安全的怎么解决呢
)
-
[
1.2. Collection 子接口之 List
](
#12-collection-子接口之-list
)
-
[
1.2.1. Arraylist 和 Vector 的区别?
](
#121-arraylist-和-vector-的区别
)
-
[
1.2.2. Arraylist 与 LinkedList 区别?
](
#122-arraylist-与-linkedlist-区别
)
...
...
@@ -46,13 +41,6 @@
-
[
1.5.1. 排序操作
](
#151-排序操作
)
-
[
1.5.2. 查找,替换操作
](
#152-查找替换操作
)
-
[
1.5.3. 同步控制
](
#153-同步控制
)
-
[
1.6. 其他重要问题
](
#16-其他重要问题
)
-
[
1.6.1. 什么是快速失败(fail-fast)?
](
#161-什么是快速失败fail-fast
)
-
[
1.6.2. 什么是安全失败(fail-safe)呢?
](
#162-什么是安全失败fail-safe呢
)
-
[
1.6.3. Arrays.asList()避坑指南
](
#163-arraysaslist避坑指南
)
-
[
1.6.3.1. 简介
](
#1631-简介
)
-
[
1.6.3.2. 《阿里巴巴 Java 开发手册》对其的描述
](
#1632-阿里巴巴-java-开发手册对其的描述
)
-
[
1.6.3.3. 使用时的注意事项总结
](
#1633-使用时的注意事项总结
)
<!-- /TOC -->
...
...
@@ -112,58 +100,7 @@
因为我们在实际开发中,存储的数据的类型是多种多样的,于是,就出现了“集合”,集合同样也是用来存储多个数据的。
数组的缺点是一旦声明之后,长度就不可变了;同时,声明数组时的数据类型也决定了该数组存储的数据的类型;而且,数组存储的数据是有序的、可重复的,特点单一。
但是集合提高了数据存储的灵活性,Java 集合不仅可以用来存储不同类型不同数量的对象,还可以保存具有映射关系的数据
### 1.1.6. Iterator 迭代器
#### 1.1.6.1. 迭代器 Iterator 是什么?
```
java
public
interface
Iterator
<
E
>
{
//集合中是否还有元素
boolean
hasNext
();
//获得集合中的下一个元素
E
next
();
......
}
```
`Iterator`
对象称为迭代器(设计模式的一种),迭代器可以对集合进行遍历,但每一个集合内部的数据结构可能是不尽相同的,所以每一个集合存和取都很可能是不一样的,虽然我们可以人为地在每一个类中定义
`hasNext()`
和
`next()`
方法,但这样做会让整个集合体系过于臃肿。于是就有了迭代器。
迭代器是将这样的方法抽取出接口,然后在每个类的内部,定义自己迭代方式,这样做就规定了整个集合体系的遍历方式都是
`hasNext()`
和
`next()`
方法,使用者不用管怎么实现的,会用即可。迭代器的定义为:提供一种方法访问一个容器对象中各个元素,而又不需要暴露该对象的内部细节。
#### 1.1.6.2. 迭代器 Iterator 有啥用?
`Iterator`
主要是用来遍历集合用的,它的特点是更加安全,因为它可以确保,在当前遍历的集合元素被更改的时候,就会抛出
`ConcurrentModificationException`
异常。
#### 1.1.6.3. 如何使用?
我们通过使用迭代器来遍历
`HashMap`
,演示一下 迭代器 Iterator 的使用。
```
java
Map
<
Integer
,
String
>
map
=
new
HashMap
();
map
.
put
(
1
,
"Java"
);
map
.
put
(
2
,
"C++"
);
map
.
put
(
3
,
"PHP"
);
Iterator
<
Map
.
Entry
<
Integer
,
String
>>
iterator
=
map
.
entrySet
().
iterator
();
while
(
iterator
.
hasNext
())
{
Map
.
Entry
<
Integer
,
String
>
entry
=
iterator
.
next
();
System
.
out
.
println
(
entry
.
getKey
()
+
entry
.
getValue
());
}
```
### 1.1.7. 有哪些集合是线程不安全的?怎么解决呢?
我们常用的
`Arraylist`
,
`LinkedList`
,
`Hashmap`
,
`HashSet`
,
`TreeSet`
,
`TreeMap`
,
`PriorityQueue`
都不是线程安全的。解决办法很简单,可以使用线程安全的集合来代替。
如果你要使用线程安全的集合的话,
`java.util.concurrent`
包中提供了很多并发容器供你使用:
1.
`ConcurrentHashMap`
: 可以看作是线程安全的
`HashMap`
2.
`CopyOnWriteArrayList`
:可以看作是线程安全的
`ArrayList`
,在读多写少的场合性能非常好,远远好于
`Vector`
.
3.
`ConcurrentLinkedQueue`
:高效的并发队列,使用链表实现。可以看做一个线程安全的
`LinkedList`
,这是一个非阻塞队列。
4.
`BlockingQueue`
: 这是一个接口,JDK 内部通过链表、数组等方式实现了这个接口。表示阻塞队列,非常适合用于作为数据共享的通道。
5.
`ConcurrentSkipListMap`
:跳表的实现。这是一个
`Map`
,使用跳表的数据结构进行快速查找。
但是集合提高了数据存储的灵活性,Java 集合不仅可以用来存储不同类型不同数量的对象,还可以保存具有映射关系的数据。
## 1.2. Collection 子接口之 List
...
...
@@ -675,170 +612,6 @@ synchronizedMap(Map<K,V> m) //返回由指定映射支持的同步(线程安
synchronizedSet
(
Set
<
T
>
s
)
//返回指定 set 支持的同步(线程安全的)set。
```
## 1.6. 其他重要问题
### 1.6.1. 什么是快速失败(fail-fast)?
**快速失败(fail-fast)**
是 Java 集合的一种错误检测机制。
**在使用迭代器对集合进行遍历的时候,我们在多线程下操作非安全失败(fail-safe)的集合类可能就会触发 fail-fast 机制,导致抛出 `ConcurrentModificationException` 异常。 另外,在单线程下,如果在遍历过程中对集合对象的内容进行了修改的话也会触发 fail-fast 机制。**
> 注:增强 for 循环也是借助迭代器进行遍历。
举个例子:多线程下,如果线程 1 正在对集合进行遍历,此时线程 2 对集合进行修改(增加、删除、修改),或者线程 1 在遍历过程中对集合进行修改,都会导致线程 1 抛出
`ConcurrentModificationException`
异常。
**为什么呢?**
每当迭代器使用
`hashNext()`
/
`next()`
遍历下一个元素之前,都会检测
`modCount`
变量是否为
`expectedModCount`
值,是的话就返回遍历;否则抛出异常,终止遍历。
如果我们在集合被遍历期间对其进行修改的话,就会改变
`modCount`
的值,进而导致
`modCount != expectedModCount`
,进而抛出
`ConcurrentModificationException`
异常。
> 注:通过 `Iterator` 的方法修改集合的话会修改到 `expectedModCount` 的值,所以不会抛出异常。
```
java
final
void
checkForComodification
()
{
if
(
modCount
!=
expectedModCount
)
throw
new
ConcurrentModificationException
();
}
```
好吧!相信大家已经搞懂了快速失败(fail-fast)机制以及它的原理。
我们再来趁热打铁,看一个阿里巴巴手册相关的规定:
![](
images/ad28e3ba-e419-4724-869c-73879e604da1.png
)
有了前面讲的基础,我们应该知道:使用
`Iterator`
提供的
`remove`
方法,可以修改到
`expectedModCount`
的值。所以,才不会再抛出
`ConcurrentModificationException`
异常。
### 1.6.2. 什么是安全失败(fail-safe)呢?
明白了快速失败(fail-fast)之后,安全失败(fail-safe)我们就很好理解了。
采用安全失败机制的集合容器,在遍历时不是直接在集合内容上访问的,而是先复制原有集合内容,在拷贝的集合上进行遍历。所以,在遍历过程中对原集合所作的修改并不能被迭代器检测到,故不会抛
`ConcurrentModificationException`
异常。
### 1.6.3. Arrays.asList()避坑指南
最近使用
`Arrays.asList()`
遇到了一些坑,然后在网上看到这篇文章:
[
Java Array to List Examples
](
http://javadevnotes.com/java-array-to-list-examples
)
感觉挺不错的,但是还不是特别全面。所以,自己对于这块小知识点进行了简单的总结。
#### 1.6.3.1. 简介
`Arrays.asList()`
在平时开发中还是比较常见的,我们可以使用它将一个数组转换为一个 List 集合。
```
java
String
[]
myArray
=
{
"Apple"
,
"Banana"
,
"Orange"
}
;
List
<
String
>
myList
=
Arrays
.
asList
(
myArray
);
//上面两个语句等价于下面一条语句
List
<
String
>
myList
=
Arrays
.
asList
(
"Apple"
,
"Banana"
,
"Orange"
);
```
JDK 源码对于这个方法的说明:
```
java
/**
*返回由指定数组支持的固定大小的列表。此方法作为基于数组和基于集合的API之间的桥梁,与 Collection.toArray()结合使用。返回的List是可序列化并实现RandomAccess接口。
*/
public
static
<
T
>
List
<
T
>
asList
(
T
...
a
)
{
return
new
ArrayList
<>(
a
);
}
```
#### 1.6.3.2. 《阿里巴巴 Java 开发手册》对其的描述
`Arrays.asList()`
将数组转换为集合后,底层其实还是数组,《阿里巴巴 Java 开发手册》对于这个方法有如下描述:
![
阿里巴巴Java开发手-Arrays.asList()方法
](
<
https://my-blog-to-use.oss-cn-beijing.aliyuncs.com/2019-6/阿里巴巴Java开发手-Arrays.asList()方法.png
>
)
#### 1.6.3.3. 使用时的注意事项总结
**传递的数组必须是对象数组,而不是基本类型。**
`Arrays.asList()`
是泛型方法,传入的对象必须是对象数组。
```
java
int
[]
myArray
=
{
1
,
2
,
3
};
List
myList
=
Arrays
.
asList
(
myArray
);
System
.
out
.
println
(
myList
.
size
());
//1
System
.
out
.
println
(
myList
.
get
(
0
));
//数组地址值
System
.
out
.
println
(
myList
.
get
(
1
));
//报错:ArrayIndexOutOfBoundsException
int
[]
array
=(
int
[])
myList
.
get
(
0
);
System
.
out
.
println
(
array
[
0
]);
//1
```
当传入一个原生数据类型数组时,
`Arrays.asList()`
的真正得到的参数就不是数组中的元素,而是数组对象本身!此时 List 的唯一元素就是这个数组,这也就解释了上面的代码。
我们使用包装类型数组就可以解决这个问题。
```
java
Integer
[]
myArray
=
{
1
,
2
,
3
};
```
**使用集合的修改方法:`add()`、`remove()`、`clear()`会抛出异常。**
```
java
List
myList
=
Arrays
.
asList
(
1
,
2
,
3
);
myList
.
add
(
4
);
//运行时报错:UnsupportedOperationException
myList
.
remove
(
1
);
//运行时报错:UnsupportedOperationException
myList
.
clear
();
//运行时报错:UnsupportedOperationException
```
`Arrays.asList()`
方法返回的并不是
`java.util.ArrayList`
,而是
`java.util.Arrays`
的一个内部类,这个内部类并没有实现集合的修改方法或者说并没有重写这些方法。
```
java
List
myList
=
Arrays
.
asList
(
1
,
2
,
3
);
System
.
out
.
println
(
myList
.
getClass
());
//class java.util.Arrays$ArrayList
```
下图是
`java.util.Arrays$ArrayList`
的简易源码,我们可以看到这个类重写的方法有哪些。
```
java
private
static
class
ArrayList
<
E
>
extends
AbstractList
<
E
>
implements
RandomAccess
,
java
.
io
.
Serializable
{
...
@Override
public
E
get
(
int
index
)
{
...
}
@Override
public
E
set
(
int
index
,
E
element
)
{
...
}
@Override
public
int
indexOf
(
Object
o
)
{
...
}
@Override
public
boolean
contains
(
Object
o
)
{
...
}
@Override
public
void
forEach
(
Consumer
<?
super
E
>
action
)
{
...
}
@Override
public
void
replaceAll
(
UnaryOperator
<
E
>
operator
)
{
...
}
@Override
public
void
sort
(
Comparator
<?
super
E
>
c
)
{
...
}
}
```
我们再看一下
`java.util.AbstractList`
的
`remove()`
方法,这样我们就明白为啥会抛出
`UnsupportedOperationException`
。
```
java
public
E
remove
(
int
index
)
{
throw
new
UnsupportedOperationException
();
}
```
**《Java面试突击》:**
Java 程序员面试必备的《Java面试突击》V3.0 PDF 版本扫码关注下面的公众号,在后台回复
**"面试突击"**
即可免费领取!
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录