学习java集合框架,让我们先从一张图看起
首先聊一下我对于java整个集合的理解,无论底层实现是链表或者二叉树,还是数组或者令大家闻风丧胆的红黑树,说白了就是存放和查询数据,以及数据的增加 比较相同与否等。
两个接口派生而出,Collection和Map 也是集合框架的根接口,下面又包含了一下子接口和实现类
从list接口说起,他的实现类首先都是是有序的(先进先出,stack除外,因为他是栈),并且是可以重复的,而且允许存放多个null 且整个集合框架中只有list的实现类可以按照下标获得元素( get() )。基本的增删查改方法在此我就不赘述了!对了,还有一个重要的知识点,就是遍历集合,我们需要用到迭代器。建议用迭代器,当然也可用增强for循环,但是会丢失下标的索引,再此我也不想赘述了,大家可以去试试。
ArrayList 和LinkedList以及vector
ArrayList底层是基于数组实现的,相比于LinkedList查询快。但是增删效率低 且线程不安全。
LinkedList底层是基于链表实现的,相比于ArrayList 查询就慢(因为链表每一次都是从第一个元素开始查找来进行比对),但是增删快。且线程不安全
vector底层是基于数组实现的,查询快,增删慢,线程安全,但是,运行效率慢!
接下来我们说一下set ,特点是元素无顺序(TreeSet有序,后面细说),不能重复,只能存一个null元素,遍历我们依然可以采用迭代器。
HashSet和 TreeSet和 LinkedHashSet
Set接口规定了元素不能重复,HashSet作为实现类就实现了这个规则。那么Hashet是如何实现这个不重复的功能呢? 是不是这样实现的呢: 假设集合中已经有1000个各不相同元素了,现在我们想向其中添加第1001个元素,集合就拿着这个新元素,去与集合中已经存在的1000个旧元素,一个一个地比较,只有都不相同,才把这第1001个所谓的新元素放入集合中。 不是,不是这样的!!为什么不采取这种方法呢,因为这种方法效率太慢,它的算法复杂度为O(n)
而HashSet真正使用的算法是:哈希算法。 这个哈希算法能很快地判断出一个将要加入集合中的新元素是否在集合中已经出现过。原理是什么呢? 我们先举一个生活中的例子:
马上国庆节了,7天可以出去旅游了,那么势必要带上旅行箱,而旅行箱中的东西不应该重复。
这样每当拿到一个新的元素要放入箱子之前,要先判断该元素的类型,只有相同类型的元素才比较,不同类型的元素不用比较,如此就大大地降低了比较的次数,从而提高了判断是否重复的效率。
哈希码我觉得很有必要说一下,它是根据对象的内容计算,所以两个对象,只要内容相同,哈希码就一定也相同,但是!!哈希码相同,内容不一定相同。
为了让大家彻底明白Hash算法是怎么回事,我们自己手写一个HashSet:
所以无论Hash算法怎么变化,它一定遵循以下的步骤:
1. 计算新元素的哈希码
2. 根据哈希码找桶位
3. 判断桶位是否为空 null,如果是,就直接存入新元素
4. 如果桶位不为空,就拿着新元素去与每一个旧元素比较,都不相同才存入,有一个相同就不存入!
以上这4个步骤,就是哈希算法。
问:什么时候,我们自定义的类需要实现hashCode和equals方法呢?
答:当你想把某个类的对象存入HashSet时,就重写吧
比较器下面也说一下吧
这里就会引出一个设计原则,开闭原则!类更多的时候是发现的,当你要用的时候,请不要随便的更改作者写的方法,因为你不知道这个方法哪里又去调用,所有请方法重写吧!
LinkedHashSet底层是有序的链表
TreeSet保证了元素不会重复,当元素是字符串或者数字,它会对元素进行“自然排序”,底层是红黑树
Map分支的特点是:
1. 存放键值对
2. 键不能重复
3. 值可以重复
HashMap其实就是HashSet的底层实现! 所以我们不再赘述哈希算法。
值得一说的是,开始是16长度的数组,当存放的数组下标超过16,且单个数组对应的链表长度超过8,就会转变成红黑树。
TreeMap其实就是TreeSet的底层实现! 所以我们不再赘述!
还有就是集合工具类,里面有许多静态方法用于对集合的曾删差改以及比较。
最后有兴趣的可以再去多了接了接并发集合。