Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add:完成集合框架及源码分析 #11

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

diamondlin2016
Copy link

No description provided.

}

注视我都写在代码里面了,其实ArrayList.Iterator 就是一个对数组的遍历,较之直接 for()循环ArrayList,优点是做了 fail-fast 检查,并且增加了在遍历过程中删除的功能。

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

注释

@@ -0,0 +1,151 @@
**首先,在探索集合之前,我们先来思考一个问题,集合是什么?**

*针对一个特定的问题,如果事先不知道需要多少个对象,或者它们的持续时间有多长,那么也不知道如何保存那些对象。既然如此,怎样才能知道那些对象要求多说空间呢?事先上根本无法提前知道,除非进入运行期。

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

有个错别字,多说空间

*针对一个特定的问题,如果事先不知道需要多少个对象,或者它们的持续时间有多长,那么也不知道如何保存那些对象。既然如此,怎样才能知道那些对象要求多说空间呢?事先上根本无法提前知道,除非进入运行期。
在面向对象的设计中,大多数问题的解决办法似乎都有些轻率——只是简单地创建另一种类型的对象。用于解决特定问题的新型对象容纳了指向其他对象的引用。当然,也可以用数组来做同样的事情,那是大多数语言都具有的一种功能。 但不能只看到这一点。这种新对象通常叫作“集合”(亦叫作一个“容器”)。在 需要的时候,集合会自动扩充自己,以便适应我们在其中置入的任何东西。所以 我们事先不必知道要在一个集合里容下多少东西。只需创建一个集合,以后的工作让它自己负责好了。*

上文摘抄自《Thinking in Java》,集合解决的问题是,在编译期间不知道要多少个对象,但是数组必须在申明的时候明确指明数组长度,如果食用数组,申请太多的空间就会造成资源浪费,如果申请太少空间,就不够用。所以引出了一个概念叫“容器”,来解决这个问题,这个容器就是我们今天要研究的对象--“集合”。

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

食用数组 哈哈

@@ -0,0 +1,531 @@


# Map
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

提个建议看了你说了这么多,没有一张图来说明他的结构涨什么样,还有1.7到1.8的区别
因为我之前看的时候踩过坑。谢谢!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1.8一个 bucket 里面的元素超过8个会连边转红黑树。数据结构感觉我已经讲清楚了。。。。要去偷图嘛。。。。

Copy link

@ghost ghost left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

别着急,今天好好提意见


可能问题描述得有点抽象,我举个例子:假设有个 ArrayList 集合A,A里面包含10个元素,分别是0~9。假设线程a在获取第5个元素的过程中,线程b操作A删除了第一个元素。那么问题来了,此时a线程是获取的到结果是5,但是我的本意应该是取到结果4,此时程序发生了错误,因此产生 fail-fast 问题,遂抛出异常。

###解决方案
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MarkDown 语法错误,加个空格

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

好的

Copy link

@ghost ghost left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

集合一 初步审核

- remove():删除当前元素,非必须的方法,有需要可重写实现。
- forEachRemaining():给剩下来所有元素做了一个自定义的相同操作。非必须的方法,有需要可重写实现。

#fail-fast 与 ConcurrentModificationException
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这也是Markdown语法错误

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

已修正

可能问题描述得有点抽象,我举个例子:假设有个 ArrayList 集合A,A里面包含10个元素,分别是0~9。假设线程a在获取第5个元素的过程中,线程b操作A删除了第一个元素。那么问题来了,此时a线程是获取的到结果是5,但是我的本意应该是取到结果4,此时程序发生了错误,因此产生 fail-fast 问题,遂抛出异常。

###解决方案
1. 在遍历过程中所有涉及到改变modCount值得地方全部加上synchronized。
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AbstractList 里边的 modCount 上文没看到你做一个过渡提到过

- remove():删除当前元素,非必须的方法,有需要可重写实现。
- forEachRemaining():给剩下来所有元素做了一个自定义的相同操作。非必须的方法,有需要可重写实现。

#fail-fast 与 ConcurrentModificationException
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#fail-fast 价格空格


###解决方案
1. 在遍历过程中所有涉及到改变modCount值得地方全部加上synchronized。
2. 用 CopyOnWriteArrayList,ConcurrentHashMap 替换 ArrayList, HashMap,它们的功能和名字一样,在写入时会创建一个 copy,然后在这个 copy 版本上进行修改操作,这样就不会影响原来的迭代。不过坏处就是浪费内存。
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. CopyOnWriteArrayList,ConcurrentHashMap 替换 ArrayList, HashMap
    改为 CopyOnWriteArrayList 、ConcurrentHashMap 替换 ArrayList 、HashMap 是不是比较好
  2. 这样就不会影响原来的迭代。不过坏处就是浪费内存。
    改为 这样就不会影响原来的迭代,不过坏处就是浪费内存。
  3. 为什么要提到 ConcurrentHashMap 替换 HashMap ?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

已更正

>迭代器模式
>定义:提供一种方法访问一个容器对象中各个元素,而又不暴露该对象的内部细节。

这里我们的重点不是迭代器模式,对“迭代器模式”感兴趣的童鞋可以自行去了解一波。
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里给“迭代器模式” 文章的一个连接,而不是只只让人搜索一下,给个能点击的链接

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

好的

#fail-fast 与 ConcurrentModificationException

> fail-fast:是java集合(Collection)中的一种错误机制。当多个线程对同一个集合的内容进行操作时,就可能会产生fail-fast事件。
> ConcurrentModificationException:出现 fail-fast 问题的时候就会抛出这个异常。
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

感觉没说到具体,原因是modCount(修改的数组次数) 和 expectedModCount(期望修改的数组次数) 不一致会抛出 ConcurrentModificationException 这个错误

Copy link

@ghost ghost left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

集合二 初步审核

- List 基于数组实现的集合类,元素有序可重复
- Set 基于 HashMap 实现的集合类,无序且不能重复
- Queue 基于数组实现的集合类,模拟队列,遵循 FIFO

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

是不是也要说一下 Collections 和 Arrays 这两个工具类

- default Stream<E> parallelStream() 同上


#集合的抽象实现类 AbstractCollection
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

加个空格

前面我们讲到了集合的定义以及集合的 Iterator。我们知道集合分为 Collection和 Map,今天我们的重点是学习 Collection。

# 什么是集合
我们再来回顾一下集合解决了什么问题:*在编译期间不知道要多少个对象,但是数组必须在申明的时候明确指明数组长度,如果使用数组,申请太多的空间就会造成资源浪费,如果申请太少空间,就不够用,所以引出了一个概念叫“集合”。*
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里描述的不严谨吧,集合解决了 只有数组这种类型吗? 还是其中之一

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

已修改

- List 基于数组实现的集合类,元素有序可重复
- Set 基于 HashMap 实现的集合类,无序且不能重复
- Queue 基于数组实现的集合类,模拟队列,遵循 FIFO

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

是不是可以添加 Collections 和 Arrays 工具类的理解

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

好的,加上了

Copy link

@ghost ghost left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

集合三 初步审核完毕

小时候肯定都玩过羽毛球吧,羽毛球不经打,要经常换球,于是我买了一盒羽毛球,如下图,就是一个羽毛球盒子,最先放进去的羽毛球(栈底的),要最后才能取出来。


![](https://user-gold-cdn.xitu.io/2017/9/26/af84e454f684ae1ab3fa1587a275fef4)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

图片没有显示出来

Copy link

@ghost ghost left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

集合 (七) 初步审核


照惯例,我们来看类结构图吧~~

![](https://user-gold-cdn.xitu.io/2017/10/18/08defcae996cbe2351534ae33d7fc989)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

没有出现图片


再然后就是 key 冲突的问题。hashcode 毕竟是随机数,很大概率会造成计算出来的bucketIndex 相等。上文也说了,同一个 bucketIndex 的 HashMapEntry 就是单向链表。链表的操作比较简单,我就不再多解释了。

然后说一下加载因子,由于链表比较长,入伙 HashMap 的所有元素全部保持在同一个bucketIndex 里面,即一条单向链表,那么 HashMap 就和 LinkedArrayList 没什么区别了。所以需要引进一个加载因子来加快查找效率,就是通过消耗更多的空间来降低查找时间。加载因子只能是0~1之间,默认0.75 。加载因子是什么意思呢,就是 *HashMap 里面元素的总个数 > table.length 乘以 加载因子*(符号冲突,乘号用汉字代替)的时候,就需要执行table 的扩容操作。
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LinkedArrayList 毕竟是双向链表,HashMap 中是单链表,两者有区别的,你直接说查找 从O(n)的查找时间就得了。。。

* @return 如果插入的 key 已存在,则返回被覆盖之前的 oldValue,否则返回 null
*/
public V put(K key, V value) {
if (key == null) {//如果 key 为 null,则执行插入空 kye 的方法
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

则执行插入空 kye 的方法 kye--》key

Copy link

@ghost ghost left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

集合五 初步审核完毕


好了,开始解析~~

不知道大家记不记得一种数据结构叫二叉树,这里就是使用了二叉树的思路,所以比较难理解。
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

特殊的完全二叉树 ,这里你父节点都小于子节点,也成为最小堆 ,这里你应该表达为堆的操作比较好


进队列的数据还要进行排序,每次取都是取到元素最小值,尼玛,说好的 FIFO 呢?好吧,我暂且当这是一个取出时有顺序的队列,看起来和昨天学的 TreeSet 功能差不多哈。

PriorityQueue 叫**优先队列**,即优先把元素最小值存到队头。想象一下,使用PriorityQueue去管理一个班的学生,根据可以年龄、成绩、身高设置好对应的 Comparator ,然后就能自动从小到大排序呢。哈哈哈~
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

你举个医院看病的例子呀 这是动态插入变量的问题出来,比如 在医院病人一直在添加,而且病人分优先级,比如急诊的普通感冒的人就应该先看病,这个例子比较贴切。

我们来看 siftDown()方法~
这个方法从0角标(最顶级父节点)开始,先判断左右子节点,取较小的那个一,和父节点比较,然后再对比左右子节点。根据我们这里二叉树的特点,最终能取到最小的那个元素放到顶级父节点,保证下一次 poll能取到当前集合最小的元素。具体代码不带着读了~~

ok,PriorityQueue 看完了。
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PriorityQueue 整体解释下来,感觉有点乱

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants