1.集合类概述
当你事先不知道要存放数据的个数,或者你需要一种比数组下标存取机制更灵活的方法时,你就需要用到集合类。
集合类型主要有3种:set(集)、list(列表)和map(映射),set和list是继承自connection接口的,存放于java.util包中。
Collection是最基本的集合接口,一个Collection代表一组Object,即Collection的元素(Elements,Map提供key到value的映射
Collection
├List
│├LinkedList
│├ArrayList
│└Vector
│ └Stack
└Set
Map
├Hashtable
├HashMap
└WeakHashMap
2.Connection
2.1.List
(1)Vector:基于Array的List,其实就是封装了Array所不具备的一些功能方便我们使用,它不可能走入Array的限制。性能也就不可能超越Array。所以,在可能的情况下,我们要多运用Array。另外很重要的一点就是Vector“sychronized”的,这个也是Vector和ArrayList的唯一的区别。
(2)Stack: 这个类从Vector派生而来,并且增加了方法实现栈??一种后进先出的存储结构。
(3)ArrayList:同Vector一样是一个基于Array上的链表,但是不同的是ArrayList不是同步的。所以在性能上要比Vector优越一些,但是当运行到多线程环境中时,可需要自
己在管理线程的同步问题。
(4)LinkedList:LinkedList不同于前面两种List,它不是基于Array的,所以不受Array性能的限制。它每一个节点(Node)都包含两方面的内容:1.节点本身的数据(data);2.下一个节点的信息(nextNode)。所以当对LinkedList做添加,删除动作的时候就不用像基于Array的List一样,必须进行大量的数据移动。只要更改nextNode的相关信息就可以实现了。这就是LinkedList的优势。
List总结:
a. 所有的List中只能容纳单个不同类型的对象组成的表,而不是Key-Value键值对。例如:[ tom,1,c ];
b. 所有的List中可以有相同的元素,例如Vector中可以有 [ tom,koo,too,koo ];
c. 所有的List中可以有null元素,例如[ tom,null,1 ];
d. 基于Array的List(Vector,ArrayList)(顺序表)适合查询,而LinkedList(链表)适合添加,删除操作。
注意:ArrayList与Vector不同点
a.同步性:Vector是线程安全的,也就是说是同步的,而ArrayList是线程序不安全的,不是同步的
b.数据增长:当需要增长时,Vector默认增长为原来一培,而ArrayList却是原来的一半
2.2.Set
(1)HashSet:虽然Set同List都实现了Collection接口,但是他们的实现方式却大不一样。List基本上都是以Array为基础。但是Set则是在HashMap的基础上来实现的,这个就是Set和List的根本区别。HashSet的存储方式是把HashMap中的Key作为Set的对应存储项。看看HashSet的add(Object obj)方法的实现就可以一目了然了。
public boolean add(Object obj)
{
return map.put(obj, PRESENT) == null;
}
这个也是为什么在Set中不能像在List中一样有重复的项的根本原因,因为HashMap的key是不能有重复的。
(2)LinkedHashSet:HashSet的一个子类,一个链表。
(3)TreeSet:SortedSet的子类,它不同于HashSet的根本就是TreeSet是有序的。它是通过SortedMap来实现的。
Set总结:
a.Set实现的基础是Map(HashMap);
b.Set中的元素是不能重复的,如果使用add(Object obj)方法添加已经存在的对象,则会覆盖前面的对象
2.3.迭代器iterator
通常遍历List和Set都是使用迭代器iterator进行遍历
Iterator it = list.iterator(); while(it.hasNext()) { Object o=(Object)it.next(); ... }
另外注意list和set的一些常用方法:
boolean add(Object)//确保容器持有此参数。如果没有将此参数添加进容器则返回false。 boolean addAll(Collection)//添加参数中的所有元素。只要添加了任意元素就返回true。 void clear( )//移除容器中的所有元素. boolean contains(Object)//如果容器已经持有参数则返回true boolean containsAll(Collection)//如果容器持有参数中的所有元素则返回true boolean isEmpty( )//容器中没有元素时返回true Iterator iterator( )//返回一个Iterator,可以用来遍历容器中的元素。 boolean remove(Object)//如果参数在容器中,则移除此元素的一个实例。如果做了移除动作则返回true。 boolean removeAll(Collection)//移除参数中的所有元素。只要有移除动作发生就返回true. boolean retainAll(Collection)//只保存参数中的元素只要Collection发生了改变就返回true. int size( )//返回容器中元素的数目 Object[] toArray( )//返回一个数组,包含容器中的所有元素。 Object[] toArray(Object[] a)//返回一个数组,包含容器中的所有元素,其类型与数组a的类型相同,而不是单纯的Object
3.Map
3.1.常用Map简介
(1)HashTable:实现一个映象,所有的键必须非空。为了能高效的工作,定义键的类必须实现hashcode()方法和equal()方法。这个类是前面java实现的一个继承,并且通常能在实现映象的其他类中更好的使用。
(2)HashMap:实现一个映象,允许存储空对象,而且允许键是空(由于键必须是唯一的,当然只能有一个)。
(3)WeakHashMap:实现这样一个映象:通常如果一个键对一个对象而言不再被引用,键/对象对将被舍弃。这与HashMap形成对照,映象中的键维持键/对象对的生命周期,尽管使用映象的程序不再有对键的引用,并且因此不能检索对象。
(4)TreeMap:实现这样一个映象,对象是按键升序排列的
注意:HashMap与HashTable的不同点:
a.历史原因:Hashtable是基于陈旧的Dictionary类的,HashMap是Java 1.2引进的Map接口的一个实现
b.同步性:Hashtable是线程安全的,也就是说是同步的,而HashMap是线程序不安全的,不是同步的
c.值:只有HashMap可以让你将空值作为一个表的条目的key或value
3.2.Map接口常用方法介绍
我们先介绍一下 Map 接口本身,以便了解所有实现的共同点。 Map 接口定义了四种类型的方法,每个 Map 都包含这些方法。
(1)覆盖和比较的方法
equals(Object o):比较指定对象与此 Map 的等价性
hashCode():返回此 Map 的哈希码
(2)构建和更新的方法
put(Object key, Object value):将指定值与指定键相关联
putAll(Map t):将指定 Map 中的所有映射复制到此 map
remove(Object key):从 Map 中删除键和关联的值
clear():从 Map 中删除所有映射
(3)迭代与检索的方法
迭代Map并没有最直接的方法,一般是通过以下三种视图:
Set entrySet():有键值对 Iterator keyValuePairs = aMap.entrySet().iterator();
Set keySet():所有键 Iterator keys = aMap.keySet().iterator();
Connection values():所有值 Iterator values = aMap.values().iterator();
int mapsize = aMap.size(); Iterator keyValuePairs1 = aMap.entrySet().iterator(); for (int i = 0; i < mapsize; i++) { Map.Entry entry = (Map.Entry) keyValuePairs1.next(); Object key = entry.getKey(); Object value = entry.getValue(); ... } Object[] keyValuePairs2 = aMap.entrySet().toArray(); for (int i = 0; i < rem; i++) { { Map.Entry entry = (Map.Entry) keyValuePairs2[i]; Object key = entry.getKey(); Object value = entry.getValue(); ... } //(通常第一种方法比第二种方法要快一些)
(4)访问和测试的方法
get(Object key):返回与指定键关联的值
containsKey(Object key):假如 Map 包含指定键的映射,则返回 true
containsValue(Object value):假如此 Map 将一个或多个键映射到指定值,则返回 true (containsValue比containsKey时间长得多)
isEmpty():假如 Map 不包含键-值映射,则返回 true
size():返回 Map 中的键-值映射的数目
3.3.内部哈希: 哈希映射技术
几乎所有通用 Map 都使用哈希映射。 这是一种将元素映射到数组的非常简单的机制,您应了解哈希映射的工作原理,以便充分利用 Map。
哈希映射结构由一个存储元素的内部数组组成。 由于内部采用数组存储,因此必然存在一个用于确定任意键访问数组的索引机制。 实际上,该机制需要提供一个小于数组大小的整数索引值。 该机制称作哈希函数。 在 Java 基于哈希的 Map 中,哈希函数将对象转换为一个适合内部数组的整数。 您不必为寻找一个易于使用的哈希函数而大伤脑筋: 每个对象都包含一个返回整数值的 hashCode() 方法。 要将该值映射到数组,只需将其转换为一个正值,然后在将该值除以数组大小后取余数即可。 以下是一个简单的、适用于任何
对象的 Java 哈希函数
int hashvalue = Maths.abs(key.hashCode()) % table.length;
(% 二进制运算符(称作模)将左侧的值除以右侧的值,然后返回整数形式的余数。)
实际上,在 1.4 版发布之前,这就是各种基于哈希的 Map 类所使用的哈希函数。 但假如您查看一下代码,您将看到
int hashvalue = (key.hashCode() & 0x7FFFFFFF) % table.length;
它实际上是使用更快机制获取正值的同一函数。 在 1.4 版中,HashMap 类实现使用一个不同且更复杂的哈希函数,该函数基于