在使用java的时候,我们都会遇到使用集合(collection)的时候,但是java api提供了多种集合的实现。
总的说来,java api中所用的集合类,都是实现了collection接口,他的一个类继承结构如下:
collection<--list<--vector
collection<--list<--arraylist
collection<--list<--linkedlist
collection<--set<--hashset
collection<--set<--hashset<--linkedhashset
collection<--set<--sortedset<--treeset
vector : 基于array的list,其实就是封装了array所不具备的一些功能方便我们使用,它不可能走出array的限制。性能也就不可能超越array。所以,在可能的情况下,我们要多运用array。另外很重要的一点就是vector"sychronized"的,这个也是vector和arraylist的唯一的区别。
arraylist:同vector一样是一个基于array上的链表,但是不同的是arraylist不是同步的。所以在性能上要比vector优越一些,但是当运行到多线程环境中时,可需要自己在管理线程的同步问题。
linkedlist:linkedlist不同于前面两种list,它不是基于array的,所以不受array性能的限制。它每一个节点(node)都包含两方面的内容:1.节点本身的数据(data);2.下一个节点的信息(nextnode)。所以当对linkedlist做添加,删除动作的时候就不用像基于array的list一样,必须进行大量的数据移动。只要更改nextnode的相关信息就可以实现了。这就是linkedlist的优势。
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(链表)适合添加,删除操作。
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是不能有重复的。
linkedhashset:hashset的一个子类,一个链表。
treeset:sortedset的子类,它不同于hashset的根本就是treeset是有序的。它是通过sortedmap来实现的。
set总结:
1. set实现的基础是map(hashmap);
2. set中的元素是不能重复的,如果使用add(object obj)方法添加已经存在的对象,则会覆盖前面的对象。
Vector v = new Vector();
......
......
方法1 :
for(int i; i< v.size();i++) {
}
方法2:
for (Enumeration e = vecFiles.elements(); e.hasMoreElements();) {
}
HashMap Hashtable LinkedHashMap 和TreeMap
java为数据结构中的映射定义了一个接口java.util.Map;它有四个实现类,分别是HashMap Hashtable LinkedHashMap 和TreeMap
Map主要用于存储健值对,根据键得到值,因此不允许键重复,但允许值重复。
Hashmap 是一个 最常用的Map,它根据键的HashCode 值存储数据,根据键可以直接获取它的值,具有很快的访问速度。HashMap最多只允许一条记录的键为Null;允许多条记录的值为Null;HashMap不支持线程的同步,即任一时刻可以有多个线程同时写HashMap;可能会导致数据的不一致。如果需要同步,可以用Collections的synchronizedMap方法使HashMap具有同步的能力.
Hashtable 与 HashMap类似,不同的是:它不允许记录的键或者值为空;它支持线程的同步,即任一时刻只有一个线程能写Hashtable,因此也导致了Hashtale在写入时会比较慢。
LinkedHashMap保存了记录的插入顺序,在用Iterator遍历LinkedHashMap时,先得到的记录肯定是先插入的.在遍历的时候会比HashMap慢。
TreeMap能够把它保存的记录根据键排序,默认是按升序排序,也可以指定排序的比较器,当用Iterator 遍历TreeMap时,得到的记录是排过序的。
例子如下:
import java.util.*;
public class TestMap {
/**
* 初始化一个Map
*
* @param map
*/
public static void init(Map map)
{
if (map != null)
{
String key = null;
for (int i = 5; i > 0; i--)
{
key = new Integer(i).toString() + ".0";
map.put(key, key.toString());
// Map中的键是不重复的,如果插入两个键值一样的记录,
// 那么后插入的记录会覆盖先插入的记录
map.put(key, key.toString() + "0");
}
}
}
/**
* 输出一个Map
*
* @param map
*/
public static void output(Map map)
{
if (map != null)
{
Object key = null;
Object value = null;
// 使用迭代器遍历Map的键,根据键取值
Iterator it = map.keySet().iterator();
while (it.hasNext())
{
key = it.next();
value = map.get(key);
System.out.println("key: " + key + "; value: " + value);
}
// 或者使用迭代器遍历Map的记录Map.Entry
Map.Entry entry = null;
it = map.entrySet().iterator();
while (it.hasNext())
{
// 一个Map.Entry代表一条记录
entry = (Map.Entry) it.next();
// 通过entry可以获得记录的键和值
// System.out.println("key: " + entry.getKey() + "; value: " +
// entry.getValue());
}
}
}
/**
* 判断map是否包含某个键
*
* @param map
* @param key
* @return
*/
public static boolean containsKey(Map map, Object key)
{
if (map != null)
{
return map.containsKey(key);
}
return false;
}
/**
* 判断map是否包含某个值
*
* @param map
* @param value
* @return
*/
public static boolean containsValue(Map map, Object value)
{
if (map != null)
{
return map.containsValue(value);
}
return false;
}
/**
* 演示HashMap
*/
public static void testHashMap()
{
Map myMap = new HashMap();
init(myMap);
// HashMap的键可以为null
myMap.put(null, "ddd");
// HashMap的值可以为null
myMap.put("aaa", null);
output(myMap);
}
/**
* 演示Hashtable
*/
public static void testHashtable()
{
Map myMap = new Hashtable();
init(myMap);
// Hashtable的键不能为null
// myMap.put(null,"ddd");
// Hashtable的值不能为null
// myMap.put("aaa", null);
output(myMap);
}
/**
* 演示LinkedHashMap
*/
public static void testLinkedHashMap()
{
Map myMap = new LinkedHashMap();
init(myMap);
// LinkedHashMap的键可以为null
myMap.put(null, "ddd");
// LinkedHashMap的值可以为null
myMap.put("aaa", null);
output(myMap);
}
/**
* 演示TreeMap
*/
public static void testTreeMap()
{
Map myMap = new TreeMap();
init(myMap);
// TreeMap的键不能为null
// myMap.put(null,"ddd");
// TreeMap的值不能为null
// myMap.put("aaa", null);
output(myMap);
}
public static void main(String[] args)
{
System.out.println("采用HashMap");
TestMap.testHashMap();
System.out.println("采用Hashtable");
TestMap.testHashtable();
System.out.println("采用LinkedHashMap");
TestMap.testLinkedHashMap();
System.out.println("采用TreeMap");
TestMap.testTreeMap();
Map myMap = new HashMap();
TestMap.init(myMap);
System.out.println("新初始化一个Map: myMap");
TestMap.output(myMap);
// 清空Map
myMap.clear();
System.out.println("将myMap clear后,myMap空了么? " + myMap.isEmpty());
TestMap.output(myMap);
myMap.put("aaa", "aaaa");
myMap.put("bbb", "bbbb");
// 判断Map是否包含某键或者某值
System.out
.println("myMap包含键aaa? " + TestMap.containsKey(myMap, "aaa"));
System.out.println("myMap包含值aaaa? "
+ TestMap.containsValue(myMap, "aaaa"));
// 根据键删除Map中的记录
myMap.remove("aaa");
System.out.println("删除键aaa后,myMap包含键aaa? "
+ TestMap.containsKey(myMap, "aaa"));
// 获取Map的记录数
System.out.println("myMap包含的记录数: " + myMap.size());
// Map.Entry 和 Map.entrySet()2008年04月02日 星期三 下午 05:29
Map<String, String> map = new HashMap<String, String>();
map.put("a", "李荣");
map.put("b", "张明");
map.put("c", "小张");
// 方法1:用entrySet()
Iterator it = map.entrySet().iterator();
while (it.hasNext())
{
Map.Entry<String, String> m = (Map.Entry<String, String>) it.next();
System.out.println("键:" + m.getKey() + " 值:" + m.getValue());
}
// 方法2:直接在循环中
for (Map.Entry<String, String> m : map.entrySet())
{
System.out.println("键:" + m.getKey() + " 值:" + m.getValue());
}
}
}
输出:
采用HashMap
key: 2.0; value: 2.00
key: null; value: ddd
key: 5.0; value: 5.00
key: aaa; value: null
key: 3.0; value: 3.00
key: 1.0; value: 1.00
key: 4.0; value: 4.00
采用Hashtable
key: 4.0; value: 4.00
key: 1.0; value: 1.00
key: 3.0; value: 3.00
key: 5.0; value: 5.00
key: 2.0; value: 2.00
采用LinkedHashMap
key: 5.0; value: 5.00
key: 4.0; value: 4.00
key: 3.0; value: 3.00
key: 2.0; value: 2.00
key: 1.0; value: 1.00
key: null; value: ddd
key: aaa; value: null
采用TreeMap
key: 1.0; value: 1.00
key: 2.0; value: 2.00
key: 3.0; value: 3.00
key: 4.0; value: 4.00
key: 5.0; value: 5.00
新初始化一个Map: myMap
key: 2.0; value: 2.00
key: 5.0; value: 5.00
key: 3.0; value: 3.00
key: 1.0; value: 1.00
key: 4.0; value: 4.00
将myMap clear后,myMap空了么? true
myMap包含键aaa? true
myMap包含值aaaa? true
删除键aaa后,myMap包含键aaa? false
myMap包含的记录数: 1
键:a 值:李荣
键:c 值:小张
键:b 值:张明
键:a 值:李荣
键:c 值:小张
键:b 值:张明
java.util.Set接口
已知子接口: SortedSet
所有以知实现类:AbstractSet,CopyOnWriteArraySet,EnumSet,HashSet,LinkedHashSet,TreeSet
public interface Set extends Collection
不能包含重复元素.set不包含满足element1.equals(element2)的元素对,并且只能有一个null
方法集同java.util.Collection
Java.util.HashSet
java.lang.Object
java.util.AbstractCollection
java.util.AbstractSet
java.util.HashSet
public class HashSet extends AbstractSet implements Set,Cloneable,Serializable ;
此实现不是同步的。 如果多个线程同时访问一个集合,而其中至少一个线程修改了该集合,那么它必须 保持外部同步。这通常是通过对自然封装该集合的对象执行同步操作来完成的。如果不存在这样的对象,则应该使用 Collections.synchronizedSet 方法来“包装”集合。最好在创建时完成这一操作,以防止对 HashSet 实例进行意外的不同步访问:
Set s = Collections.synchronizedSet(new HashSet(...));
构造函数:
HashSet() 构造一个新的空集合,其底层HashMap实例的默认初始容量是16,加载因子0.75
HashSet(Collection c) 构造一个包含指定collection中的元素的新的set
HashSet(int initialCapacity) 构造一个新的空集合,其底层HashMap实例具有指定的初始容量和默认的加载因子.
HashSet(int initialCapacity,float loadFactory) 构造一个新的空集合,其底层HashMap实例具有指定的初始容量和加载因子.
其他方法同Set.
java.util.TreeSet
java.lang.Object
java.util.AbstractCollection
java.util.AbstractSet
java.util.TreeSet
public class TreeSet extends AbstractSet
implements SortedSet,Cloneable,Serializable
同步处理:
SortedSet s = Collections.synchronizedSortedSet(new TreeSet(...));
构造函数:
TreeSet() 构造一个新的空Set,该Set按照元素的自然顺序排序.
TreeSet(Collection c) 构造一个新的set,包含指定的collection中的元素,这个新的set按照 元素的自然顺序排列.
TreeSet(Comparator c) 构造一个新的空 set,该 set 根据指定的比较器进行排序。
TreeSet(SortedSet c) 构造一个新的set,该 set 所包含的元素与指定的已排序 set 包含的 元素相同,并按照相同的顺序对元素进行排序.
方法:(同set的不列出)
Object clone() 返回TreeSet实例的浅表复制.
Object first() 返回已排序set中当前的第一个(最小)元素.
Object last() 返回已排序set中当前的最后一个(最大)元素.
SortedSet subSet(Object fromElement,Object toElement) 返回此set的部分视图,其元素从 fromElement包括到toElement(不包括).
SortedSet tailSet(Object fromElement)返回此set的部分视图,其元素>=fromelement
SortedSet headSet(Object toElement) 返回此set的部分视图,要求其元素小于toElement
ex:
import java.util.Comparator;
import java.util.Iterator;
import java.util.TreeSet;
public class CollectionTool {
public CollectionTool()
{
}
public static void main(String[] args) throws Exception
{
TreeSet ts = new TreeSet();
ts.add("dd");
ts.add("aa");
ts.add("cc");
ts.add("bb");
TreeSet anotherts = (TreeSet) ts.clone();
Iterator it = anotherts.iterator();
System.out.println("TreeSet:Clone方法实例");
while (it.hasNext())
{
System.out.println(it.next());
}
System.out.println("TreeSet:comparator构造方法实例");
TreeSet s = new TreeSet(new MyComparator());
s.add("aa");
s.add("cc");
s.add("dd");
s.add("bb");
Iterator its = s.iterator();
while (its.hasNext())
{
System.out.println(its.next());
}
}
}
class MyComparator implements Comparator {
public int compare(Object s1, Object s2)
{
String str1 = (String) s1;
String str2 = (String) s2;
return str1.compareTo(str2);
}
}
输出:
TreeSet:Clone方法实例
aa
bb
cc
dd
TreeSet:comparator构造方法实例
aa
bb
cc
dd