Java集合

一、Set和Map
Set代表一种集合元素无序、集合元素不可重复的集合,Map代表一种由多个key-value对组成的集合,可以这么说,Map集合是Set集合的拓展。
Map和Set的关系:Map集合的Key具有一个特征:所有key不能重复,并且没有顺序,也就是说,如果将Map集合中的所有Key集中起来,那这些key就组成了一个set集合。对于map而言,相当于每个元素都是key-value的Set集合。

1、HashMap和HashSet
HashSet:系统采用Hash算法决定集合元素的存储位置,这样可以保证快速存取集合元素。
HashMap:系统将Value作为key的附属,系统根据Hash算法来决定key的存储位置,这样可以保证快速存取集合Key,而value总是跟随key存储。
note:集合存放的只是对象的引用。

HashMap put步骤:
1,根据key的keyCode计算Hash值
2,搜索指定hash值在对应table中的索引
3,如果i处索引处的Entry不为null,通过循环不断遍历e元素的下一个元素
4,找到指定key与需要放入的key相等,新添加Entry的value将覆盖原有Entry的value,但key不会覆盖
5,如果i索引处的Entry为null,表明此处还没有Entry
6,将key,value添加到i索引处
note:当系统决定存储HashMap中的key-value对时,完全没有考虑Entry中的value,而仅仅只是根据key来计算并决定每个Entry的存储位置,在key的hash如果通过equals比较两个Entry的key发现相等,就会替换掉原有entry中value值,如果不相等,新添加的Entry将与原有Entry形成Entry链。addEntry()方法。

HashMap构造器,默认初始容量为16,如果需要指定初始容量,最好指定为2的n次方。
当HashMap的每个bucket里存储的Entry只是单个Entry,即没有通过指针产生Entry链时,此时的HashMap具有最好的性能。

负载因子:默认为0.75,增大负载因子可以减小Hash表(实际上就是Entry数组)所占用的内存空间,但会增加查询数据的时间开销,减小负载因子会提高数据查询的性能,但会增加Hash表所占用的内存空间。

HashSet是基于HashMap实现的,底层仍然采用HashMap来保存所有的元素。封装了一个HashMap对象来存储所有的集合元素。所有放入HashSet中的集合元素实际上由HashMap的key来保存,而HashMap的value则存储了一个静态的Object对象。因此HashSet和HashMap在实现本质上是相同的。

当试图把某个类的对象当成HashMap的key,或者试图将这个类的对象放入HashSet中保存时,重写equals方法和hashCode方法很重要,而且这两个方法的返回值必需保持一致。

2、TreeMap和TreeSet
HashSet底层依赖于HashMap实现,TreeSet底层则采用一个NavigableMap来保存TreeSet集合的元素,由于NavigableMap只是一个接口,因此底层仍然采用TreeMap来保存Set集合中的所有元素。
TreeMap,底层采用红黑树的排序二叉树来保存Map中的每个Entry,每个Entry都被当成红黑树的一个节点来看待。

TreeMap添加元素、取出元素的性能都比HashMap低,这些操作都需要通过循环找到新增Entry的插入位置,因此比较好性能,优势在于:TreeMap中所有的Entry总是按key根据指定排序规则保存有序状态,TreeSet中所有元素总是根据指定排序规则保持有序状态。

二、Map和List
Map接口提供了get(Key)方法允许对象根据key获取value.
List接口提供了get(int index)方法允许List对象根据元素索引来取得value.

List相当于所有key都是int类型的Map,也可以说Map相当于索引是任意类型的List.

ArrayList和LinkedList
List三个主要实现类:ArrayList、Vector、LinkedList
Vector还有一个Stack子类,仅在Vector的基础上增加了5个方法,Stack和Vector都是线程安全的类。
在无需保证线程安全的情况下,推荐使用ArrayDeque来代替Stack类。
Deque代表双端队列这种数据结构,他既有队列的先进先出性质,也具有栈的性质,既是队列,也是栈。
ArrayList和ArrayDeque底层都是基于数组实现的,只是所提供的方法不同。

Vector和ArrayList的区别
1,Vector和ArrayList都继承自List,底层都是基于数组,但是ArrayList使用transient修饰底层数组,保证序列化ArrayList对象的时候不会直接序列化底层数组,而是通过writeObject和readObject来实现定制序列化,Vector没有实现。
因此ArrayList比Vector的序列化实现更安全。
2,Vector是线程安全的,ArrayList不是。
3,数组扩充:
ArrayList:int newCapacity = (oldCapacity3)/2+1 //将新容量扩充为原来的1.5倍
Vector:int newCapacity = (capacityIncrement>0)?(oldCapacity+capacityIncrement):(oldCapacity
2); //如果capacityIncrement>0,新容量 = oldCapacity+capacityIncrement,否则扩充为原来的两倍。

ArrayList和LinkedList的实现差异
1,List代表一种线性表的数据结构,ArrayList则是一种顺序存储的线性表。
2,ArrayList底层采用数组来存储每个集合元素。LinkedList是一种链式存储的线性表。其本质上是一个双向链表,不仅实现了List接口,还实现了Deque接口。也就是说LinkedList不仅可以当成双向链表使用,还可以当成栈来使用,还可以当成队列来使用。
3,ArrayList添加、删除集合元素时,ArrayList底层都需要对数组进行“整体搬家”,性能非常差。

ArrayList和LinkedList的性能分析和使用场景
1,当程序需要以get(int index)方法获取指定索引处的元素时,ArrayList>LinkedList,
2,当程序调用add(int index,Object obj)向List集合添加元素时,ArrayList需要对底层数组元素进行整体搬家,如果添加元素导致集合长度将要超过底层数组长度,ArrayList必须新建一个长度为原来长度1.5倍的数组,再有垃圾回收机制回收原有数组,系统开销较大。对于LinkedList而言,他的开销主要集中在根据index找到元素的过程,即使如此:LinkedList>ArrayList
3,当程序调用remove(int index)方法删除index处的元素时,ArrayList同样需要对底层数组元素进行整体搬家,但是无需考虑创建新的数组,因此:LinkedList约等于ArrayList
4,当程序调用add(Object obj)时,大多数时候无需对数组进行整体搬家,但是如果添加元素导致集合大小大于数组大小,ArrayList必须新建一个长度为原来长度1.5倍的数组,这样开销就比较大了,LinkedList则有比较好的性能。因此:LinkedList>ArrayList

你可能感兴趣的:(Java集合)