Java中集合的分类
1.集合分类
Collection:单列集合的父类
Map:key-value形式的键值对集合
2.Collection集合的子类
常见子类有List,Set,Queue
List:有序的可重复的
Set:无序的不可重复的
Queue:队列,先进先出原则(FIFO,First In First Out)
3.List集合的子类
常见的子类有ArrayList,LinkedList,Vector
3.1 ArrayList
举个例子:
ArrayList就像一个筒子楼,一般筒子楼里面住的都是认识的人,你只要找到一个,就相当于找到了所有人。
简单来说:
ArrayList内部是一个数组,数组的默认大小是10个单位。基于数组的特性,所以ArrayList在存储的物理空间上是连续的,所以查询比较快,而增删的话,就需要整个空间从插入位置后移,删除位置前移,所以比较耗时。
从源码来说:
ArrayList刚被创建的时候,数组的大小为0,当第一次添加数据的时候,数组的大小才被扩容到10。
当ArrayList中装满10个元素之后,会通过grow()增长方法,把数组大小扩容为原来的1.5倍,由于是int类型进行的运算,所以如果出现奇数的话,就会丢弃小数点之后的值。
举例:现在数组的大小是15的话,也就是第二次扩容之后,15+15/2 = 22.5,但使用的时候是22。
3.2 LinkedList
举个例子:
LinkedList就像是住在城市,彼此住的都挺远的,你想找到你三舅,你就必须先找到你大舅,然后通过大舅,找到你二舅,然后通过二舅,找到你三舅。
LinkedList内部是由双向链表来完成的,没有所谓的扩容机制。
从物理存储的角度来说,元素与元素之间的内存是不连续的。所以在查找起来的话,会比较慢,但是正是由于他的不连续,所以增删的话,速度比ArrayList要快。
他的每个元素是由三部分组成的,分别是上一个节点的地址,当前元素,下一个节点的地址。
3.3 Vector
Vector底层的数据结构与ArrayList是完全一致的,唯一的区别就是他的增删改方法都加了关键字synchronized关键字,所以是线程安全的。
这个类已经被遗弃了,也就是这样Vector
4.Set集合
常见的子类有三种:HashSet,LinkedHashSet,TreeSet
4.1 HashSet
举个例子:
HashSet就像每个人一样,肯定不完全一样。如果完全一样了,就肯定是同一个人。
HashSet底层是由HashMap实现的,但是由于HashMap是一个key-value形式的,所以在实现的时候,HashSet的值,存放在HashMap的key中,而HashMap的value其实是一个final型的Object空对象。
大家都知道,HashMap的key不能重复,所以就形成了HashSet的无序性。
而在遍历HashSet的时候,其实就是在遍历HashMap的key的集合。如果你遍历过HashMap的话,你应该知道可以遍历HashMap的key的集合,方法就是keySet()。
判断唯一性的标准:通过hashCode()方法,和equals()方法共同来决定的
4.2 LinkedHashSet
举个例子:
按照某种顺序排队的人。首先每个人都不一样,但是我们就必须按照年龄啊,个头啊,给这些人排个顺序出来。
LinkedHashSet是基于HashSet实现的。他的内部是由HashMap的子类,LinkedHashMap来实现的。
通过插入的顺序,来保证里面的元素的排列。
4.3 TreeSet
要想理解TreeSet,首先我们先要了解Tree树是个什么东西。
请看下图:
大家可以看到,我们刚才讲的List也好,或者其他的Set也好,结构都是单列的。也就是一条线。而树这种结构,是分叉的。这种结构的好处就是,查询的效率比较高。因为如果我们要想查到9这个数,只需要查询3次即可。而如果把树转化成List这种形式的话,就需要经过4次。如果把这个深度加深的话,遍历的次数会更多。
基于Tree这种结构,我们再来看看TreeSet。可以发现,TreeSet是把Set中的元素的存储结构转化为Tree这种结构。所以从查询效率的角度来看,比HashSet和LinkedHashSet都要快很多。