浅谈集合
1、集合的分类
分类:
下面的都是从底层分析区别:
1、ArrayList和linkedlist和vector的区别:
这三个集合都实现了list接口
- (1)ArrayList的底层是数组,而linkedlist的底层是双向链表vector的底层也是数组,
(2)vector是线程安全的,而ArrayList和linkedlist是线程不安全的,因为vector的很多方法是用synchronize修饰的,而不是vector这个类
(3)对于查询而言,ArrayList和vector的查询速度更快,因为可以直接定位,数组的空间是连续的,直接通过索引查找,而链表的空间不是连续是,前一个结点只保存了后一个结点的地址,所以不能直接定位查询
(4)对于插入、删除而言,linkedlist的效率要大于ArrayList和vector,因为ArrayList的插入删除要移动操作元素后面的所有元素,而链表只需要将地址给前后的结点就可以了
2、treeset和hashset的区别
这里的无序都是指存入和顺序和取出的顺序不一致
首先set集合是无序的,但是treeset集合实现了set接口,它是有序的,这里就体现了接口的含义(接口是一种功能规范)
区别:
- (1)treeset的底层是二叉树,不能保存空值,按照我们制定的顺序存储,是有序的,不许有null值
(2)hashset的底层是hash表,是无序的,可以有null值,但是只能有一个null值 (3)两者都是线程不安全的
(4)hashset保证元素唯一的方法:通过对象的hashcode和equals方法来完成,所以hashset的元素必须要重写hashcode和equals方法
(5)treeset是通过compareTo方法,比较元素来判断是否有相同的元素
treeset如何进行排序的
如果元素自身具备比较功能,treeset中的元素要实现Comparable接口,然后重写compareTo方法,元素自身不具备比较功能,则需要实现Comparator接口,并覆盖其compare方法。
3、hashmap、hashtable和currentHashmap的区别
hashmap和hashtable都是实现了map接口,但是hashtable的实现是基于Dictionary抽象类的
- (1)hashmap的底层是数组+链表**,可以存储一个null键和多个null值,线程不安全**
hashmap的初始size=16,扩容:newsize=oldsize2,size一定是2的n次幂
当map中的元素总数操作entry数组的75%时,触发扩容操作,为了减少链表长度,元素分配更均匀,计算index方法:index=hash&(tab.length-1)
(2)hashtable的底层是数组+链表实现,无论是key还是value都不能为null,线程安全,实现线程安全的方式是在修改数据时锁住整个hashtable,所以效率低
初始size=11,newsize=oldsize2+1; 计算index方法: index = (hash &
0x7FFFFFFF) % tab.length
(3)currenthashmap底层采用分段的数组+链表实现,线程安全,通过锁分段技术保证线程安全的
通过把整个Map分为N个Segment,可以提供相同的线程安全,但是效率提升N倍,默认提升16倍。(读操作不加锁,由于HashEntry的value变量是
volatile的,也能保证读取到最新的值。)
Hashtable的synchronized是针对整张Hash表的,即每次锁住整张表让线程独占
(4)Hashtable与HashMap另一个区别是HashMap的迭代器(Iterator)是fail-fast迭代器,而Hashtable的enumerator迭代器不是fail-fast的。所以当有其它线程改变了HashMap的结构(增加或者移除元素),将会抛出ConcurrentModificationException,但迭代器本身的remove()方法移除元素则不会抛出ConcurrentModificationException异常。但这并不是一个一定发生的行为,要看JVM。