今天的任务是把容器这一章节的知识总结梳理一遍。
总的来说,容器这一章节就像是数据结构的一个章节,我们依次学习了顺序表、链表和哈希表,这三种线性结构(像二叉树之类的非线性存储结构还未探究)。
首先我们通过Collection接口延伸出List接口和Set接口,然后靠部分源码简单分析它们各自的实现类: ArrayList、LinkedList、HashSet 。
- ArrayList存储数据的方式是顺序表,实质上就是按顺序存放的数组呗。它最关键的地方是——扩容。这个实现起来其实并不是特别困难,只要在需要扩容时创建出长度更长的新数组,并将原数组内容全部拷贝下来就行啦(Java已经写了这个方法:Arrays.copyof(…) )。
- LinkedList存储数据的方式是链表,实际上就是一个个相互独立的内存空间靠存储与自己相邻空间的地址的方式来产生关联的结构。它的关键点是——基础的指针操作。
- HashSet存储数据的方式是哈希表,实质上哈希表就是数组,但存储数据不是按顺序来的。HashSet是简化版的HashMap。它的关键点在于——理解HashMap?
其次,就是Map接口,并且靠部分源码简单分析它的实现类HashMap。
- Map接口是专门用来存储“键值对”的,而哈希表的特性正好完美契合了这种结构。因此HashMap是实现Map接口的类中最常见的。它的关键点在于——哈希函数的选择、解决哈希冲突的方式以及对哈希表的扩容。哈希函数要能将数据均匀分布开; 解决哈希冲突的方式是拉链法或者叫链地址法; 在哈希表的扩容时,需要对哈希表进行重建。
Collection集合相关类是有统一的方式遍历底层的数据结构的,这个方式就是——Iterator迭代器。而HashMap并不是Collection的实现类,但是可以靠转化的方式变成一个Set再处理(这又分了两种方式:一种是键值对整体替换;另一种是就先保留Key舍弃Value,最后通过key访问Value),也就意味着目前学过的容器类都可以使用Iterator迭代器进行遍历。使用这种方式遍历容器,和自己写遍历方法相比安全且快捷,何乐而不为呢?但是有时候我也在想一个问题:前人栽树,后人乘凉,如果后人只知乘凉而忘了自己也是“后人”的“前人”,这颗树它能撑多久?
明天开始下一个重点—— IO !