Skip to content

Commit

Permalink
完善部分集合类有关的知识点
Browse files Browse the repository at this point in the history
  • Loading branch information
hollis.zhl committed Apr 21, 2019
1 parent 7d2595e commit 7afcfa7
Show file tree
Hide file tree
Showing 11 changed files with 160 additions and 8 deletions.
30 changes: 22 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ replaceFirst、replaceAll、replace区别、

[字符串拼接的几种方式和区别](/basics/java-basic/string-concat.md)

String.valueOf和Integer.toString的区别
[String.valueOf和Integer.toString的区别](/basics/java-basic/value-of-vs-to-string.md)

[switch对String的支持](/basics/java-basic/switch-string.md)

Expand All @@ -95,21 +95,35 @@ transient、instanceof、volatile、synchronized、final、static、const 原理

#### 集合类

常用集合类的使用、ArrayList和LinkedList和Vector的区别 、[SynchronizedList和Vector的区别](/basics/java-basic/synchronizedlist-vector.md)、HashMap、HashTable、ConcurrentHashMap区别、
常用集合类的使用

Set和List区别?Set如何保证元素不重复?
[ArrayList和LinkedList和Vector的区别](/basics/java-basic/arraylist-vs-linkedlist-vs-vector.md)

[Java 8中stream相关用法](/basics/java-basic/stream.md)apache集合处理工具类的使用、不同版本的JDK中HashMap的实现的区别以及原因
[SynchronizedList和Vector的区别](/basics/java-basic/synchronizedlist-vector.md)

Collection和Collections区别
[HashMap、HashTable、ConcurrentHashMap区别](/basics/java-basic/HashMap-HashTable-ConcurrentHashMap.md)

Arrays.asList获得的List使用时需要注意什么
[Set和List区别?](/basics/java-basic/set-vs-list.md)

Enumeration和Iterator区别
[Set如何保证元素不重复?](/basics/java-basic/set-repetition.md)

[Java 8中stream相关用法](/basics/java-basic/stream.md)

apache集合处理工具类的使用、

不同版本的JDK中HashMap的实现的区别以及原因

[Collection和Collections区别](/basics/java-basic/Collection-vs-Collections.md)

[Arrays.asList获得的List使用时需要注意什么](/basics/java-basic/Arrays-asList.md)

[Enumeration和Iterator区别](/basics/java-basic/Enumeration-vs-Iterator.md)

[fail-fast 和 fail-safe](/basics/java-basic/fail-fast-vs-fail-safe.md)

CopyOnWriteArrayList、ConcurrentSkipListMap
[CopyOnWriteArrayList](/basics/java-basic/CopyOnWriteArrayList.md)

[ConcurrentSkipListMap](/basics/java-basic/ConcurrentSkipListMap.md)

#### 枚举

Expand Down
3 changes: 3 additions & 0 deletions basics/java-basic/Arrays-asList.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
1. asList 得到的只是一个 Arrays 的内部类,一个原来数组的视图 List,因此如果对它进行增删操作会报错

2. 用 ArrayList 的构造器可以将其转变成真正的 ArrayList
7 changes: 7 additions & 0 deletions basics/java-basic/Collection-vs-Collections.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Collection 是一个集合接口。
它提供了对集合对象进行基本操作的通用接口方法。Collection接口在Java 类库中有很多具体的实现。是list,set等的父接口。

Collections 是一个包装类。
它包含有各种有关集合操作的静态多态方法。此类不能实例化,就像一个工具类,服务于Java的Collection框架。

日常开发中,不仅要了解Java中的Collection及其子类的用法,还要了解Collections用法。可以提升很多处理集合类的效率。
14 changes: 14 additions & 0 deletions basics/java-basic/ConcurrentSkipListMap.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
ConcurrentSkipListMap是一个内部使用跳表,并且支持排序和并发的一个Map,是线程安全的。一般很少会被用到,也是一个比较偏门的数据结构。

简单介绍下跳表(
跳表是一种允许在一个有顺序的序列中进行快速查询的数据结构。

在普通的顺序链表中查询一个元素,需要从链表头部开始一个一个节点进行遍历,然后找到节点。如图1。

跳表可以解决这种查询时间过长,其元素遍历的图示如图2,跳表是一种使用”空间换时间”的概念用来提高查询效率的链表。

);

ConcurrentSkipListMap 和 ConcurrentHashMap 的主要区别:
a.底层实现方式不同。ConcurrentSkipListMap底层基于跳表。ConcurrentHashMap底层基于Hash桶和红黑树。
b.ConcurrentHashMap不支持排序。ConcurrentSkipListMap支持排序。
18 changes: 18 additions & 0 deletions basics/java-basic/CopyOnWriteArrayList.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
Copy-On-Write简称COW,是一种用于程序设计中的优化策略。其基本思路是,从一开始大家都在共享同一个内容,当某个人想要修改这个内容的时候,才会真正把内容Copy出去形成一个新的内容然后再改,这是一种延时懒惰策略。从JDK1.5开始Java并发包里提供了两个使用CopyOnWrite机制实现的并发容器,它们是CopyOnWriteArrayList和CopyOnWriteArraySet。CopyOnWrite容器非常有用,可以在非常多的并发场景中使用到。

CopyOnWriteArrayList相当于线程安全的ArrayList,CopyOnWriteArrayList使用了一种叫写时复制的方法,当有新元素add到CopyOnWriteArrayList时,先从原有的数组中拷贝一份出来,然后在新的数组做写操作,写完之后,再将原来的数组引用指向到新数组。

这样做的好处是我们可以对CopyOnWrite容器进行并发的读,而不需要加锁,因为当前容器不会添加任何元素。所以CopyOnWrite容器也是一种读写分离的思想,读和写不同的容器。

注意:CopyOnWriteArrayList的整个add操作都是在锁的保护下进行的。也就是说add方法是线程安全的。

CopyOnWrite并发容器用于读多写少的并发场景。比如白名单,黑名单,商品类目的访问和更新场景。


和ArrayList不同的是,它具有以下特性:

支持高效率并发且是线程安全的
因为通常需要复制整个基础数组,所以可变操作(add()、set() 和 remove() 等等)的开销很大
迭代器支持hasNext(), next()等不可变操作,但不支持可变 remove()等操作
使用迭代器进行遍历的速度很快,并且不会与其他线程发生冲突。在构造迭代器时,迭代器依赖于不变的数组快照

11 changes: 11 additions & 0 deletions basics/java-basic/Enumeration-vs-Iterator.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
函数接口不同

Enumeration只有2个函数接口。通过Enumeration,我们只能读取集合的数据,而不能对数据进行修改。
Iterator只有3个函数接口。Iterator除了能读取集合的数据之外,也能数据进行删除操作。

Iterator支持fail-fast机制,而Enumeration不支持。

Enumeration 是JDK 1.0添加的接口。使用到它的函数包括Vector、Hashtable等类,这些类都是JDK 1.0中加入的,Enumeration存在的目的就是为它们提供遍历接口。Enumeration本身并没有支持同步,而在Vector、Hashtable实现Enumeration时,添加了同步。
而Iterator 是JDK 1.2才添加的接口,它也是为了HashMap、ArrayList等集合提供遍历接口。Iterator是支持fail-fast机制的:当多个线程对同一个集合的内容进行操作时,就可能会产生fail-fast事件。

注意:Enumeration迭代器只能遍历Vector、Hashtable这种古老的集合,因此通常不要使用它,除非在某些极端情况下,不得不使用Enumeration,否则都应该选择Iterator迭代器。
37 changes: 37 additions & 0 deletions basics/java-basic/HashMap-HashTable-ConcurrentHashMap.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
### HashMap和HashTable有何不同?


线程安全:

HashTable 中的方法是同步的,而HashMap中的方法在默认情况下是非同步的。在多线程并发的环境下,可以直接使用HashTable,但是要使用HashMap的话就要自己增加同步处理了。

继承关系:
HashTable是基于陈旧的Dictionary类继承来的。
HashMap继承的抽象类AbstractMap实现了Map接口。


允不允许null值:
HashTable中,key和value都不允许出现null值,否则会抛出NullPointerException异常。
HashMap中,null可以作为键,这样的键只有一个;可以有一个或多个键所对应的值为null。


默认初始容量和扩容机制:
HashTable中的hash数组初始大小是11,增加的方式是 old*2+1。HashMap中hash数组的默认大小是16,而且一定是2的指数。原因参考全网把Map中的hash()分析的最透彻的文章,别无二家。-HollisChuang's Blog

哈希值的使用不同 :
HashTable直接使用对象的hashCode。
HashMap重新计算hash值。


遍历方式的内部实现上不同 :
Hashtable、HashMap都使用了 Iterator。而由于历史原因,Hashtable还使用了Enumeration的方式 。
HashMap 实现 Iterator,支持fast-fail,Hashtable的 Iterator 遍历支持fast-fail,用 Enumeration 不支持 fast-fail

### HashMap 和 ConcurrentHashMap 的区别?

ConcurrentHashMap和HashMap的实现方式不一样,虽然都是使用桶数组实现的,但是还是有区别,ConcurrentHashMap对桶数组进行了分段,而HashMap并没有。


ConcurrentHashMap在每一个分段上都用锁进行了保护。HashMap没有锁机制。所以,前者线程安全的,后者不是线程安全的。

PS:以上区别基于jdk1.8以前的版本。
17 changes: 17 additions & 0 deletions basics/java-basic/arraylist-vs-linkedlist-vs-vector.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
List主要有ArrayList、LinkedList与Vector几种实现。

这三者都实现了List 接口,使用方式也很相似,主要区别在于因为实现方式的不同,所以对不同的操作具有不同的效率。

ArrayList 是一个可改变大小的数组.当更多的元素加入到ArrayList中时,其大小将会动态地增长.内部的元素可以直接通过get与set方法进行访问,因为ArrayList本质上就是一个数组.

LinkedList 是一个双链表,在添加和删除元素时具有比ArrayList更好的性能.但在get与set方面弱于ArrayList.

当然,这些对比都是指数据量很大或者操作很频繁的情况下的对比,如果数据和运算量很小,那么对比将失去意义.

Vector 和ArrayList类似,但属于强同步类。如果你的程序本身是线程安全的(thread-safe,没有在多个线程之间共享同一个集合/对象),那么使用ArrayList是更好的选择。

Vector和ArrayList在更多元素添加进来时会请求更大的空间。Vector每次请求其大小的双倍空间,而ArrayList每次对size增长50%.

而 LinkedList 还实现了 Queue 接口,该接口比List提供了更多的方法,包括 offer(),peek(),poll()等.

注意: 默认情况下ArrayList的初始容量非常小,所以如果可以预估数据量的话,分配一个较大的初始值属于最佳实践,这样可以减少调整大小的开销。
10 changes: 10 additions & 0 deletions basics/java-basic/set-repetition.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
在Java的Set体系中,根据实现方式不同主要分为两大类。HashSet和TreeSet。

1、TreeSet 是二差树实现的,Treeset中的数据是自动排好序的,不允许放入null值
2、HashSet 是哈希表实现的,HashSet中的数据是无序的,可以放入null,但只能放入一个null,两者中的值都不能重复,就如数据库中唯一约束

在HashSet中,基本的操作都是有HashMap底层实现的,因为HashSet底层是用HashMap存储数据的。当向HashSet中添加元素的时候,首先计算元素的hashcode值,然后通过扰动计算和按位与的方式计算出这个元素的存储位置,如果这个位置位空,就将元素添加进去;如果不为空,则用equals方法比较元素是否相等,相等就不添加,否则找一个空位添加。

TreeSet的底层是TreeMap的keySet(),而TreeMap是基于红黑树实现的,红黑树是一种平衡二叉查找树,它能保证任何一个节点的左右子树的高度差不会超过较矮的那棵的一倍。

TreeMap是按key排序的,元素在插入TreeSet时compareTo()方法要被调用,所以TreeSet中的元素要实现Comparable接口。TreeSet作为一种Set,它不允许出现重复元素。TreeSet是用compareTo()来判断重复元素的。
11 changes: 11 additions & 0 deletions basics/java-basic/set-vs-list.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
List,Set都是继承自Collection接口。都是用来存储一组相同类型的元素的。

List特点:元素有放入顺序,元素可重复 。

有顺序,即先放入的元素排在前面。

Set特点:元素无放入顺序,元素不可重复。

无顺序,即先放入的元素不一定排在前面。
不可重复,即相同元素在set中只会保留一份。所以,有些场景下,set可以用来去重。
不过需要注意的是,set在元素插入时是要有一定的方法来判断元素是否重复的。这个方法很重要,决定了set中可以保存哪些元素。
10 changes: 10 additions & 0 deletions basics/java-basic/value-of-vs-to-string.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
我们有三种方式将一个int类型的变量变成呢过String类型,那么他们有什么区别?

1.int i = 5;
2.String i1 = "" + i;
3.String i2 = String.valueOf(i);
4.String i3 = Integer.toString(i);

第三行和第四行没有任何区别,因为String.valueOf(i)也是调用Integer.toString(i)来实现的。

第二行代码其实是String i1 = (new StringBuilder()).append(i).toString();,首先创建一个StringBuilder对象,然后再调用append方法,再调用toString方法。

0 comments on commit 7afcfa7

Please sign in to comment.