数组和集合的效率问题数组是JAVA语言内置的数据类型,它是一个线性的序列,所以它可以快速的访问其他的元素。但是速度是要有代价的,当你创建了一个数组之后,它的容量就固定了,而且在其生命周期里是不能改变的。还有一点,JAVA里面的数组是会做边界检查的,所以当你越界访问时,会抛出RuntimeException,所以不用担心在C或C++因为不做边界检查而出现的问题了,当然边界检查是以牺牲效率为代价的。数组与其它容器类的区别体现在三个方面:效率、类型识别和可以持有primitives。
int sum = 0;
int[] arrays = new int[100000000];
ArrayList list = new ArrayList();
for(int i=0;i<100000000;i++) {
list.add(0);
}
Long time01 = System.currentTimeMillis();
for(int i=0;i<100000000;i++) {
sum += arrays[i%10];
}
Long time02 = System.currentTimeMillis();
System.out.println("数组求和所花费的时间:"+(time02-time01)+"毫秒");
Long time03 = System.currentTimeMillis();
for(int i=0;i<100000000;i++) {
sum += list.get(i%10);
}
Long time04 = System.currentTimeMillis();
System.out.println("集合求和所花费的时间:"+(time04-time03)+"毫秒");
数组求和所花费的时间:144毫秒
集合求和所花费的时间:175毫秒
在追求计算效率的地方,我们应该用数组。
2. 集合Collection 接口的接口 对象的集合
├ List 子接口 按进入先后有序保存 可重复
│├ LinkedList 接口实现类 链表 插入删除 没有同步 线程不安全
│├ ArrayList 接口实现类 数组 随机访问 没有同步 线程不安全
│└ Vector 接口实现类 数组 同步 线程安全
│ └ Stack
└ Set 子接口 仅接收一次,并做内部排序
├ HashSet
│ └ LinkedHashSet
└ TreeSet
List容器侧重于顺序,添加元素是按顺序保存,并且允许重复元素,使用此容器能够保证元素下标位置的精确。
用户能够使用索引(也就是位置,可以理解为数组中的下标)来访问 List 中的元素。
对于 Set ,只关心某元素是否属于 Set (不允许有相同元素 ),而不关心它的顺序。Map 接口 键值对的集合
├ Hashtable 接口实现类 同步 线程安全
├ HashMap 接口实现类 没有同步 线程不安全
│├ LinkedHashMap
│└ WeakHashMap
├ TreeMap
└ IdentifyHashMap
对于 Map ,最大的特点是键值映射,且为一一映射,key不能重复value可以,所以是用键来索引值。
方法 put(Object key, Object value) 添加一个“值” (真实的值 ) 和与“值”相关联的“键” (key) ( 索引 ) 。方法 get(Object key) 返回与给定“键”相关联的“值”。
Map 同样对每个元素保存一份,但这是基于 ” 键 ” 的, Map 也有内置的排序方法,因而不关心元素添加的顺序(我们无法干涉元素的顺序)。
如果添加元素的顺序对你很重要,应该使用 LinkedHashSet 或者 LinkedHashMap.
对于效率, Map 由于采用了哈希散列,查找元素时明显比 ArrayList 快。
HashMap线程不安全,效率比HashTable高。反之HashTable线程更安全。HashMap不安全是因为底层维护了一个数组,在多线程访问这个数组就不安全。
综上所述,在集合中Map效率最高,那Map和数组谁更快?
insert和delete时,Map效率高,因为底层是链表(长度比较小的时候)。
select和update的时候,数组最快,毕竟有下标,也就是有地址,直达列车。在查改方面数组可以通过索引迅速确定位置,而链表只能依次寻找,所以数组有着无法匹敌的优势。而在增删方面,数组每次插入元素都要将该元素后面的所有元素向后挪动一位,删除则将该元素之后所有元素向前移动一位。而链表在插入元素的时候,只需将该元素前驱的指针指向本身,将本身的指针指向后驱,删除则将该元素的前驱指向该元素的后驱。相比之下,链表确实优势挺大。
在容器长度很大(几千上万时),增删改查都是数组有优势。