最近一段时间再补基础,因此看了一些源码。 其中自然是要看数据结构的,因此看了看java的集合框架,跟着网上的大牛。虽然大牛们已经写的十分的完善了,但是实践出真知,自己还是跟着大牛的思路去看看了看源码,原计划2天的空余时间看完的,没想到尽管只是看,没有深入理解都已经花了接近一周的时间。 为了方便自己理解记忆,特此开贴记录一下。
先上图吧。
没想到画这东西出来密密麻麻的我自己都惊讶了,可见前辈们付出了多少的心血在上面,才能有这么完善的体系。
说说自己的理解吧:
一:Iterator接口,其字面意思为 迭代器,事实上它却也是完成迭代的功能。通过Iterator接口与Collection联系起来。 也就是 Collection依赖于Iterator。因此,Collection及其子类都会依赖于Iterator,都能实现迭代的功能。
二:我们平常常用的集合类有: LinkList,ArrayList,不常用的有 :Vector及其子类Stack。 可以看到,我们平常能接触到的集合类都继承自AbstractList,AbstractList作为一个抽象类,通常帮我们完成了一个体系的骨架。 例如: 接口是对某一种功能的抽象,它通常只面向需求,例如需要什么,完成什么功能,达到什么效果等待。 而抽象类,或者说抽象基类,则会为完成该功能封装一些需要的东西,以及限定子类必须初始化什么东西,实现那些函数,保证抽象基类的子类被实例化后,能够形成一个健全的体系。(指从接口到抽象类,在到实例化的类中所有遇到的接口或者函数都被实现,完成某一种功能所必需的数据在实例化时就能被准备好。保证这一体系能够正常运行。)
三:LinkList是基于链式存储,其内部有一个私有关键类:Node,节点的意思,作为链式成员,也负责前后联系。实现了Queue,Dequeue接口,可以用作队列,双端队列(应该也能作为栈,因为它们都是线性的,从这一点来说,应该Collection的子类都能作为队列,栈等数据结构操作。不知道对不对。)所以它的存取效率应该是较高的,但是查询的效率较低。(效率应该都是跟数据量挂钩的,平时数据量不够的话,效率一说可能感觉不太真实。)。 ArrayList是基于数组实现的,因此它的存取效率可能要低一点,因为他会判断容量是否够大,不够大就会进行相应的扩容,相应的就增加了执行的命令数,自然效率要低一些。 Vector的话也是基于数组实现,大部分内容跟ArrayList差不多,因为它们都继承自同一个抽象基类。最主要的区别应该是它是线程安全的。
四:Map跟Collection不存在上下级关系,或者说是同级关系更好理解一些吧。 以前一直在用,一直也存在一些疑惑。
另外一点想补充的就是Map,跟Collection都是接口,而我们更多的是将其看作为了类,因为我们常常在思考,collection的本质是什么,或者说Map的本质是什么。 因为我们经常听说它们,那么难免就越想越想不明白。 我的一点理解就是:它们并不是由什么什么构成,由什么什么实现,它们本质上只是一个接口,代表的是一组或者说一些功能的抽象,是一团方法的集合。我们去想它的本质是什么,这个就很尴尬了,因为它本身什么都没有。我们应该思考的是ArrayList或者说LinkList,Vector的本质是什么。
另外,Collection系,与Map系为什么说同级关系更好理解一些呢? 因为从表现形式上,Collection是基于一维的,是线性的关系,而Map是二维的,是平面的关系。即,key,value。 Map系之所以能够实现二维的数据存储,是通过泛型实现的。 而查看源码我们能比较明晰的看到,每一个泛型,K,V它们又都是属于Collection系的,能够实现特定的功能。但是其中的算法还是比较复杂的,HashMap,TreeMap的源码大概在4000行左右,除去空行跟注释应该也有2000多行的样子,它们各自的内部又定义了一系列的私有内部类,负责处理各自的逻辑。 HashTable则相当于Map的外甥吧,这样好理解一点,看图也能说明,其代码应该在1000行左右。
还有就是,Map接口中有一个Entry接口,这也是我们平时写循环语句: for(Map.Entry e: ...)的由来,那么这个Entry是什么? 为什么Entry能够在一个Map里面遍历。 查看HashMap 的源码可以很容易知道: 有一个 Node内部类实现了Entry接口,这里的Node 跟LinkList里面的大同小异,都是节点的意思。 另外,HashMap有一个 成员变量,Node[]table,这是一个Node型的数组,查看源码也能够发现,无论是put,还是set方法,都是在这二者做文章。 TreeMap类似。 因此Map不谈,只看HashMap的话,我们可以说其本质便是Node。 至于为什么K会保证不重复,这里有一个忘了交代的了,那就是Set。
五:Set接口能够保证一个不重复的集合。 从图中可以看到,Set接口继承自Collection,AbstractSet实现了Set接口,并且继承自AbstractCollection,(这也许就是传说中的多态吧)。查看Set接口,可以发现其没有新增的功能接口,最主要的是覆盖了几个父类的接口,并且提供了默认实现方法,大致是Hashcode,equals,还有个啥记不得了。 但是这两个方法足以说明问题。
总结:通过这次的实践,进一步理解到基础的重要性。同时对于我感觉算是一个惊喜的收获就是: 不要再对着接口抠破脑袋的去思考,它的本质是什么,它是如何实现之类的话题。 另外附上我们通信技术基础老师一句比较经典的台词:....人的一生只能研究一小点。
注:本文系四川旅游学院16级信息管理与信息系统专业陈开海投稿。