不知道为什么,昨天写的这篇文章不见了。早上重新补上来吧,以后写东西还是得先写在电脑里面,然后在发布出来才行。
集合类一直让我感觉头痛,因为我老是搞混淆,可能是基础不够扎实的原因吧。现在专们花个时间来总结下,以后混淆了就直接来查看便是。那么,就先来看看各种集合类的比较表吧。
先写下我自己的记忆方式:
Collection:把它当做是一个集合,没有任何限制条件的集合,那么它里面的元素是可以重复的,并且也是杂乱无序的;
Set:其实它也是一个集合,不过它在Collection上加了一个限制条件就是元素不可以重复;
List:可以把它看成是一个实实在在的数组,对于数组而言,是有序的而且元素也是可以重复的;
Map:其实是键值对存储,那么跟链表差不多,如果是HashMap的话,节点的存储随机的,也就是无序,键当然是唯一的,所以HashMap是无序且key不可重复的,而对于TreeMap来说的话,它就相当于一棵树,那么它是有序的,当然,key也是不可重复的;
总而言之:只要带Hash的都是无序的,只要是当做实实在在的数组存储的都是有序的,而像Collection和Set之类的作为集合操作的,都是无序的,允不允许重复还得看谁是最原始的不加任何限制的,即Collection可重复,Set不可重复。
集合类比较表
|
是否有序 |
是否允许元素重复 |
|
Collection |
否 |
是 |
|
List |
是 |
是 |
|
Set |
AbstractSet |
否 |
否 |
HashSet |
|||
TreeSet |
是(用二叉树排序) |
||
Map |
AbstractMap |
否 |
使用key-value来映射和存储数据,Key必须惟一,value可以重复 |
HashMap |
|||
TreeMap |
是(用二叉树排序) |
常用的集合类介绍
Collection<--List<--Vector
Collection<--List<--ArrayList
Collection<--List<--LinkedList
Collection<--Set<--HashSet
Collection<--Set<--HashSet<--LinkedHashSet
Collection<--Set<--SortedSet<--TreeSet
Set(集):(HashSet)无序不重复
List(ArrayList和LinkedList)(列表):无序可重复
Map(映射,键值对):(HashMap)有序key值不重复
Collection:父接口
Set:接口---实现类: HashSet、LinkedHashSet
List:接口---实现类:LinkedList,Vector,ArrayList
SortedSet:接口---实现类:TreeSet
1.List总结
(1)所有的List中只能容纳单个不同类型的对象组成的表,而不是Key-Value键值对。例如:[ tom,1,c ];
(2) 所有的List中可以有相同的元素,例如Vector中可以有 [ tom,koo,too,koo ];
(3) 所有的List中可以有null元素,例如[ tom,null,1 ];
(4) 基于Array的List(Vector,ArrayList)适合查询,而LinkedList(链表)适合添加,删除操作。
List:有序列表,允许存放重复的元素;
实现类:
(1)ArrayList:数组实现,查询快,增删慢,线程不安全,轻量级;
(2)LinkedList:链表实现,增删快,查询慢;
(3)Vector:数组实现,线程安全,重量级 。
例:levit应用中使用集合分布表:
集合类型 |
应用数量 |
ArrayList |
184处 |
LinkedList |
2处 |
Vector |
0 |
分析:从以上的分析结果来看ArrayList是用的最多的,Vector没有用到(有性能问题,不建议使用)。
Vector和ArrayList的区别
(1)同步性:Vector是同步的。这个类中的一些方法保证了Vector中的对象是线程安全的。而ArrayList则是异步的,因此ArrayList中的对象并不是线程安全的。因为同步的要求会影响执行的效率,所以如果不需要线程安全的集合那么使用ArrayList是一个很好的选择,这样可以避免由于同步带来的不必要的性能开销。
(2)数据增长:从内部实现机制来讲ArrayList和Vector都是使用数组(Array)来控制集合中的对象。当你向这两种类型中增加元素的时候,如果元素的数目超出了内部数组目前的长度它们都需要扩展内部数组的长度,Vector缺省情况下自动增长原来一倍的数组长度,ArrayList是原来的50%,所以最后你获得的这个集合所占的空间总是比你实际需要的要大。所以如果你要在集合中保存大量的数据那么使用Vector有一些优势,因为你可以通过设置集合的初始化大小来避免不必要的资源开销。
List遍历的三种方法
ArrayList
public static void testArrayList(){
//ArrayList 有序允许重复
List<String> list = new ArrayList<String>();
list.add("我是小颜");
list.add("我是小颜");
list.add("我是幕燃");
list.add("我是幕燃2");
//遍历第一种 get
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
//遍历第二种 Iterator
Iterator<String> it = list.iterator();
while(it.hasNext()){
String str = (String)it.next();
System.out.println(str);
}
//遍历第三种 for
for (String str : list) {
System.out.println(str);
}
}
LinkedList
public static void testLinkedList(){
//有序可重复
List<String> list = new LinkedList<String>();
list.add("我是哈哈");
list.add("我是哈哈");
list.add("我是幕燃");
list.add("我是幕燃2");
//遍历第一种 get
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
//遍历第二种 Iterator
Iterator<String> it = list.iterator();
while(it.hasNext()){
String str = (String)it.next();
System.out.println(str);
}
//遍历第三种 for
for (String str : list) {
System.out.println(str);
}
}
2.Set总结
(1)Set实现的基础是Map(HashMap);
(2) 无序集合,Set中的元素是不能重复的,如果使用add(Object obj)方法添加已经存在的对象,则会覆盖前面的对象,允许使用null元素;
(3)HashSet 的后台有一个HashMap;初始化后台容量;只不过生成一个HashSet的话,系统只提供key的访问;如果有两个Key重复,那么会覆盖之前的;
实现类HashSet:equals返回true,hashCode返回相同的整数;哈希表;存储的数据是无序的。
实现类LinkedHashSet:此实现与HashSet的不同之外在于,后者维护着一个运行于所有条目的双重链接列表。存储的数据是有序的。
子接口SortedSet,对Set排序实现类 :TreeSet:使用元素的自然顺序对元素进行排序,或者根据创建 set 时提供的 Comparator 进行排序;二叉树实现的;
Set遍历的两种方式:
public static void testSet(){
//无序不重复
Set<String> set = new HashSet<String>();
set.add("我是哈哈");
set.add("我是哈哈");
set.add("我是幕燃");
set.add("我是幕燃2");
//遍历方法一 Iterator
Iterator<String> it = set.iterator();
while(it.hasNext()){
String str = it.next().toString();
System.out.println(str);
}
//遍历方法二 for
for (String str: set) {
System.out.println(str);
}
}
3.Map总结
HashMap:键值对,key不能重复,但是value可以重复;key的实现就是HashSet;value对应着放;允许null的键或值;
Hashtable:线程安全的,不允许null的键或值;
Properties::key和value都是String类型,用来读配置文件;
TreeMap:对key排好序的Map; key 就是TreeSet,value对应每个key; key要实现Comparable接口或TreeMap有自己的构造器;
LinkedHashMap: 此实现与 HashMap的不同之处在于,后者维护着一个运行于所有条目的双重链接列表。存储的数据是有序的。
levit应用中使用集合分布表:
集合类型 |
应用数量 |
HashMap |
142处 |
Hashtable |
0 |
Properties |
0 |
TreeMap |
0 |
LinkedHashMap |
3 |
分析:从以上的分析结果来看与List的分析结果大致相同,HashMap应用场景最多。
Map遍历的五种方式
public static void testMap(){
//Map 无序key值不重复
Map<String, String> map = new HashMap<String, String>();
map.put("zhangsan", "我是张三");
map.put("devin", "我是dw");
map.put("haha", "我是哈哈");
//遍历方法一 map.keySet + for
for(String key : map.keySet()){
System.out.println("key="+ key + ",value=" + map.get(key));
}
//遍历方法二map.keySet +Iterator
Iterator<String> iterator = map.keySet().iterator();
while(iterator.hasNext()){
String key1 = iterator.next().toString();
System.out.println("key="+ key1 + ",value=" + map.get(key1));
}
//遍历方式三 map.values
for (String key2 : map.values()) {
System.out.println("value=" + key2);
}
//遍历方式四 map.entrySet + for
for(Map.Entry<String,String> entry : map.entrySet()){
System.out.println("key="+ entry.getKey() + ",value=" + entry.getValue());
}
//遍历方式五map.entrySet() + Iterator
Iterator <Map.Entry<String,String>> entry = map.entrySet().iterator();
while(entry.hasNext()){
Map.Entry<String, String> ent = entry.next();
System.out.println("key="+ ent.getKey() + ",value=" + ent.getValue());
}
}
4.两个工具类 Arrays 和 Collections
1.Arrays:此类包含用来操作数组(比如排序和搜索)的各种方法。
2.Collections:主要提供了在 collection 上进行操作的静态方法(同步集合类方法) 。
5.使用模式(源自百度百科)
在ArrayList和Vector中,从一个指定的位置(通过索引)查找数据或是在集合的末尾增加、移除一个元素所花费的时间是一样的,这个时间我们用O(1)表示。但是,如果在集合的其他位置增加或移除元素那么花费的时间会呈线形增长:O(n-i),其中n代表集合中元素的个数,i代表元素增加或移除元素的索引位置。为什么会这样呢?以为在进行上述操作的时候集合中第i和第i个元素之后的所有元素都要执行位移的操作。这一切意味着什么呢?
这意味着,你只是查找特定位置的元素或只在集合的末端增加、移除元素,那么使用Vector或ArrayList都可以。如果是其他操作,你最好选择其他的集合操作类。比如,LinkList集合类在增加或移除集合中任何位置的元素所花费的时间都是一样的—O(1),但它在索引一个元素的使用缺比较慢-O(i),其中i是索引的位置.使用ArrayList也很容易,因为你可以简单的使用索引来代替创建iterator对象的操作。LinkList也会为每个插入的元素创建对象,所有你要明白它也会带来额外的开销。
最后,在《Practical Java》一书中Peter Haggar建议使用一个简单的数组(Array)来代替Vector或ArrayList。尤其是对于执行效率要求高的程序更应如此。因为使用数组(Array)避免了同步、额外的方法调用和不必要的重新分配空间的操作。