Java集合
List与Set
List | Set | |
---|---|---|
存取顺序 | 有序 | 无序 |
有无索引 | 有索引 | 无索引 |
重复元素 | 允许重复 | 不允许重复 |
获取元素 | 能获取指定位置的元素 | 只能逐一遍历 |
ArrayList与LinkedList
ArrayList | LinkedList | |
---|---|---|
底层 | 动态数组 | 链表 |
内存存储 | 连续内存 | 可以存储在分散的内存中 |
查询元素 | 适合随机访问 | 不适合查询,需要逐一遍历 |
增删元素 | 增删慢 | 适合数据插入删除 |
ArrayList的扩容机制是当超出数组长度时会新建数组,将数据进行拷贝,再插入新的元素。若使用尾插法并且合理指定数组的初始容量,可以大大提高插入的性能,甚至会超过LInkedList的插入性能。
CopyOnWriteArrayList
实现读写分离,内部也是通过数组实现的,添加元素时会复制子一个新的数组,写操作在新数组上进行,读操作在原数组上进行,且写操作会加锁保证安全。写操作结束后会将原数组指向新数组。允许在写操作时来读取数据,大大提高了读的性能,适用于读多写少的场景,但本身比较占内存,且不实时,读操作可能读取的不是最新的数据。
HashMap、HashTable、ConcurrentHashMap
- HashMap底层是数组+链表+红黑树,JDK7是数组+链表,大体上是一个数组,每个元素又是一个单向链表,Entry实体保存:key、value、hash以及next指针。JDK8当链表中的元素超过了8,就会将链表转为红黑树,进一步提升查询性能。
- HashTable和HasnMap相似,但HashTable是线程安全的,内部方法使用synchronized修饰(全局锁),但不能存储null值。
- ConcurrentHashMap是线程安全版本的HashMap,支持并发操作,由一个个segment组成,使用分段锁机制。JDK7 底层是ReentrantLock+Segment+HashEntry,JDK8底层原理是synchronized+CAS+Node+红黑树
hashCode()与equals()
hashCode()的作用是获取哈希值(散列码),实际返回的是一个int整数,确定该对象在哈希表的索引位置,可以根据key快速检索出对应的value。hashCode()定义在JDK的Object.java中,java中的任何类都包含hashCode()函数。equals()是用于判断两个对象是否等价。
如果两个对象相等,则hashCode值相同,equals()返回true;但两个对象有相同的hashCode值,不一定是相等的;如果equals()被覆盖过,则hashCode()也必须被覆盖。
以HashSet为例,加入对象时,先计算hashCode()判断对象加入的位置,若该位置无值则直接加入,若该位置有值,会调用equals()检查两个对象是否相同,若相同则插入失败,不同则可以重新散列到其它位置。这样大大减少了equals()的次数,提高了执行速度。