jdk 的集合框架的主体结构:
接口 | 简述 | 实现 | 操作特性 | 成员要求 |
Set | 成员不能重复 | HashSet | 外部无序地遍历成员。 | 成员可为任意Object子类的对象,但如 果覆盖了equals方法,同时注意修改hashCode方法。 |
TreeSet | 外部有序地遍历成员;附加实现了 SortedSet, 支持子集等要求顺序的操作 | 成员要求实现caparable接口,或者 使用 Comparator构造TreeSet。成员一般为同 一类型。 | ||
LinkedHashSet | 外部按成员的插入顺序遍历成员 | 成员与HashSet成员类似 | ||
List | 提供基于索引的对成 员的随机访问 | ArrayList | 提供快速的基于索引的成员访问,对尾部成员 的增加和删除支持较好 | 成员可为任意Object子类的对象 |
LinkedList | 对列表中任何位置的成员的增加和删除支持较 好,但对基于索引的成员访问支持性能较差 | 成员可为任意Object子类的对象 | ||
Map | 保存键值对成员,基 于键找值操作,compareTo或compare方法对键排序 | HashMap | 能满足用户对Map的通用需求 | 键成员可为任意Object子类的对象,但 如果覆盖了equals方法,同时注意修改hashCode方法。 |
TreeMap | 支持对键有序地遍历,使用时建议先用 HashMap增加和删除成员,最后从HashMap生成TreeMap;附加实现了SortedMap接口,支持子Map等要求顺序的操作 | 键成员要求实现caparable接口,或 者使用Comparator构造TreeMap。键成员一般为同一类型。 | ||
LinkedHashMap | 保留键的插入顺序,用equals 方法检查键和值的相等性 | 成员可为任意Object子类的对象,但如 果覆盖了equals方法,同时注意修改hashCode方法。 | ||
IdentityHashMap | 使用== 来检查键和值的相等性。 | 成员使用的是严格相等 | ||
WeakHashMap | 其行为依赖于垃圾回收线程,没有绝对理由则 少用 |
Java Collections Framework成员主要包括两种类型,即:Collection和Map类型。 在Java中提供了Collection和Map接口。其中List和Set继承了Collection接口;同时用Vector、ArrayList、 LinkedList三个类实现List接口,HashSet、TreeSet实现Set接口。直接有HashTable、HashMap、 TreeMap实现Map接口。Collection----一组独立的元素,通常这些元素都服从某种规则。List必须保持元 素特定的顺序,而Set不能有重复元素。 Map----一组成对的“键值对”对象,即其元素是成对的对象,最典型的应用就是数据字典,并且还有其它广泛 的应用。另外,Map可以返回其所有键组成的Set和其所有值组成的Collection,或其键值对组成的Set,并且还可以像数组一样扩展多维 Map,只要让Map中键值对的每个“值”是一个Map即可 。Set(interface): 存入Set的每个元素必须是唯一的,因为Set不保存重复元素。加入Set的Object必须定义equals()方法以确保对象的唯一性。Set与 Collection有完全一样的接口。Set接口不保证维护元素的次序。
首先还要说一下迭代器:迭代器是一种设计模式,它是一个对象,它可以遍历 并选择序列中的对象,而开发人员不需要了解该序列的底层结构。迭代器通常被称为“轻量级”对象,因为创建它的代价小。
(1) 使用方法iterator()要求容器返回一个Iterator。第一次调用Iterator的next()方法时,它返回序列的第一个元素。
(2) 使用next()获得序列中的下一个元素。
(3) 使用hasNext()检查序列中是否还有元素。
(4) 使用remove()将迭代器新返回的元素删除。
Iterator是Java迭代器最简单的实现,为List设计的ListIterator具有更多的功能,它可以从两个方向遍历List,也可以从 List中插入和删除元素。
壹--Vector
Vector基于Array的List,性能也就不可能超越 Array,并且Vector是“sychronized”的,这个也是Vector和ArrayList的唯一的区别。
Vector
类可以实现可增长的对象数组。与数组一样,它包含可以使用整数索引进行访问的组件。但是,Vector
的大小可以根据需要增大或缩小,以适应创建 Vector
后进行添加或移除项的操作 。
用法如下:
import java.util.Vector;
public class Iterator {
@SuppressWarnings( " unchecked " )
public static void main(String[] args) {
// Vector的创建
// 使用Vector的构造方法进行创建
Vector v = new Vector( 4 );
// 向Vector中添加元素
// 使用add方法直接添加元素
v.add( " Test0 " );
v.add( " Test1 " );
v.add( " Test2 " );
v.add( " Test3 " );
v.add( " Test4 " );
// 从Vector中删除元素
v.remove( " Test0 " ); // 删除指定内容的元素
v.remove( 0 ); // 按照索引号删除元素
// 获得Vector中已有元素的个数
int size = v.size();
System.out.println( " size: " + size);
// 遍历Vector中的元素
for ( int i = 0 ;i < v.size();i ++ ){
System.out.println(v.get(i));
}
}
}
贰--ArrayList
ArrayList同Vector一样是一个基于Array的,但是不同的是ArrayList不是同步的。所以在性能上要比Vector优越一些,但是 当运行到多线程环境中时,可需要自己在管理线程的同步问题。从其命名中可以看出它是一种类似数组的形式进行存储,因此它的随机访问速度极快,动态的增加和减少元素。
import java.util.ArrayList;
import java.util.List;
import java.util.Iterator;
/**
* 迭代ArrayList()的4种方法;
*/
public class ArrayListTest {
@SuppressWarnings( " unchecked " )
public static void main(String[] args) {
List < String > list = new ArrayList < String > ();
list.add( " aaa " );
list.add( " bbb " );
list.add( " ccc " );
// 方法1
Iterator it1 = list.iterator();
while (it1.hasNext()){
System.out.println(it1.next());
}
// 方法2(与方法一大同小异)
for (Iterator it2 = list.iterator();it2.hasNext();){
System.out.println(it2.next());
}
// 方法3
for (String tmp:list){
System.out.println(tmp);
}
// 方法4
for ( int i = 0 ;i < list.size(); i ++ ){
System.out.println(list.get(i));
}
}
}
叁--LinkedList:
LinkedList不同于前面两种List,它不是基于Array的,所以不受Array性能的限制。它每一个节点(Node)都包含两 方面的内容:1.节点本身的数据(data);2.下一个节点的信息(nextNode)。所以
当对LinkedList做添加,删除动作的时候就不用像基于Array的List一样,必须进行大量的数据移动。只要更改nextNode的相关信息就 可以实现了所以它适合于进行频繁进行插入和删除操作。它具有方法addFirst()、addLast()、getFirst()、 getLast()、removeFirst()、removeLast(),这些方法(没有在任何接口或基类中定义过)使得LinkedList可以当 作堆栈、队列和双向队列使用 。 这就是
LinkedList的优势。Iterator只能对容器进行向前遍历,而 ListIterator则继承了Iterator的思想,并提供了对List进行双向遍历的方法。
import java.util.Iterator;
import java.util.LinkedList;
/**
* 迭代ArrayList()的4种方法;
*/
public class LinkedListTest
肆--HashTable
Hashtable继承Map接口,实现一个key-value映射的哈希表。任何非空(non-null)的对象都可作为key或者value。添加数 据使用put(key, value),取出数据使用get(key),这两个基本操作的时间开销为常数。
import java.util.Hashtable;
public class HastTableTest {
public static void main(String[] args) {
Hashtable < String, Integer > numbers = new Hashtable < String, Integer > ();
numbers.put( " one " , 1 );
numbers.put( " two " , 2 );
numbers.put( " three " , 3 );
Integer n = numbers.get( " two " );
if (n != null ) {
System.out.println( " two = " + n);
}
}
}
伍--HashMap
HashMap把各个Object映射起来,实现了“键-- 值”对应的快速存取。注意,次实现是不同步的。
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
public class HashMapTest {
@SuppressWarnings( " unchecked " )
public static void main(String[] args) {
HashMap < String , String > myMap = new HashMap < String , String > ();
myMap.put( " hello " , " 你 好 " );
myMap.put( " bye " , " 再 见 " );
myMap.put( " thanks " , " 谢 谢 " );
myMap.put( " ok " , " 好 的 " );
System.out.println( " --------------------遍历key和 value---------------------- " );
for (Iterator iter = myMap.entrySet().iterator();iter.hasNext();){
Map.Entry element = (Map.Entry)iter.next();
Object strKey = element.getKey();
Object strObj = element.getValue();
System.out.println( " myMap.get(/ "" +strKey+ " / " )= " + strObj);
}
System.out.println();
System.out.println( " --------------------遍历整个 HashMap---------------------- " );
Collection objs = myMap.entrySet();
for (Iterator iterator = objs.iterator(); iterator.hasNext();){
Object obj = iterator.next();
System.out.println(obj);
}
System.out.println();
System.out.println( " --------------------遍历HashMap的 key---------------------- " );
Collection keys = myMap.keySet();
for (Iterator iterator = keys.iterator(); iterator.hasNext();){
Object key = iterator.next();
System.out.println(key);
}
System.out.println();
System.out.println( " --------------------遍历HashMap的 value---------------------- " );
Collection values = myMap.values();
for (Iterator iterator = values.iterator(); iterator.hasNext();){
Object value = iterator.next();
System.out.println(value);
}
}
}
陆--TreeMap
import java.util.Iterator;
import java.util.Map;
import java.util.TreeMap;
public class TreeMapTest {
public static void main(String[] args) {
TreeMap tm = new TreeMap();
for ( int i = 0 ; i < 10 ; i ++ ) {
String a = " key " + i;
String b = " value " + i;
tm.put(a, b);
}
// 第一种方法
// 使用entrySet()方法生成一个由Map.entry对象组成的Set,
// 而Map.entry对象包括了每个元素的"键"和"值".这样就可以用 iterator了
Iterator it = tm.entrySet().iterator();
while (it.hasNext()) {
// entry的输出结果如key0=value0等
Map.Entry entry = (Map.Entry) it.next();
Object key = entry.getKey();
Object value = entry.getValue();
System.out.println(entry);
System.out.println(key);
System.out.println(value);
}
// 第二种方法
// 这是用TreeMap的keySet()方法,生成的对象是由key对象组成的 Set
// 再利用TreeMap的get(key)方法,得到对应的value值
Iterator ite = tm.keySet().iterator();
while (ite.hasNext()) {
// it.next()得到的是key,tm.get(key)得到obj
System.out.println(tm.get(ite.next()));
}
}
}
柒--LindedHashMap
LinkedHashMap扩展HashMap,以插入顺序 将关键字/值对添加进链接哈希映像中。象LinkedHashSet一样,LinkedHashMap内部也采用双重链接式列表。
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashMap;
public class LinkedHashMapTest {
@SuppressWarnings( " unchecked " )
public static void main(String[] args) {
LinkedHashMap lHashMap = new LinkedHashMap();
lHashMap.put( " One " , new Integer( 1 ));
lHashMap.put( " Two " , new Integer( 2 ));
lHashMap.put( " three " , new Integer( 3 ));
lHashMap.put( " four " , new Integer( 4 ));
System.out.println( " ~~~~~~~~~~~~~~~~~~方法一:迭代LinkedHashMap类型的 lHashMap;~~~~~~~~~~~~~~~~~~~~ " );
for (Iterator it = lHashMap.values().iterator();it.hasNext();){
System.out.println(it.next());
}
System.out.println( " ~~~~~~~~~~~~~~~~~~方法二:迭代LinkedHashMap类型的 lHashMap;~~~~~~~~~~~~~~~~~~~~ " );
Collection c = lHashMap.values();
Iterator iter = c.iterator();
while (iter.hasNext()){
System.out.println(iter.next());
}
System.out.println( " ~~~~~~~~~~~~~~~~~~Get Set view of Keys from Java LinkedHashMap;~~~~~~~~~~~~~~~~~~~~ " );
Iterator itr = lHashMap.keySet().iterator();
while (itr.hasNext()){
System.out.println(itr.next());
}
// key - 要测试其是否在此映射中存在的键
boolean blnExistKey = lHashMap.containsKey( " Two " );
System.out.println(blnExistKey);
// value - 要测试其是否在此映射中存在的值
boolean blnExistValue = lHashMap.containsValue( " 1 " );
System.out.println(blnExistValue);
System.out.println( " ~~~~~~~~~~~~~~~~~~从LinkedHashMap中移除key为 “Two”的值;~~~~~~~~~~~~~~~~~~~~ " );
Object obj = lHashMap.remove( " Two " ); // 从LinkedHashMap中移除key为“Two”的值;
System.out.println(obj + " Removed from LinkedHashMap " ); // 输出移除的值;
}
}
此类实现 Set 接口,它不保证 set 的迭代顺序;特别是它不保证该顺序恒久不变。此类为基本操作提供了稳定性能,这些基本操作包括 add 、remove 、contains 和 size;次实现是不同步的;为快速查找而设计的Set。存入HashSet的对象必须定义hashCode();
import java.util.HashSet;
import java.util.Iterator;
public class HashSetTest {
@SuppressWarnings( " unchecked " )
public static void main(String[] args)
{
HashSet hashSet = new HashSet();
String a = new String( " A " );
String b = new String( " B " );
String c = new String( " B " );
String d = " D " ;
hashSet.add(a);
hashSet.add(b);
hashSet.add(d);
System.out.println( " ~~~~~~~~~~~b和c得值相同;所以size()是3~~~~~~~~~~~ " );
System.out.println(hashSet.size());
String cz = hashSet.add(c) ? " 此对象不存在 " : " 已 经存在 " ;
System.out.println( " 测试是否可以添加对象 " + cz);
System.out.println( " ~~~~~~~~~~~测试是否为空;~~~~~~~~~~~ " );
System.out.println(hashSet.isEmpty());
System.out.println( " ~~~~~~~~~~~测试其中是否已经包含某个对象;~~~~~~~~~~~ " );
System.out.println(hashSet.contains( " A " ));
System.out.println( " ~~~~~~~~~~~迭代;~~~~~~~~~~~ " );
Iterator ir = hashSet.iterator();
while (ir.hasNext())
{
System.out.println(ir.next());
}
System.out.println( " ~~~~~~~~~~~测试某个对象是否可以删除;~~~~~~~~~~~ " );
System.out.println(hashSet.remove( " a " ));
System.out.println(hashSet.remove( " A " ));
System.out.println( " ~~~~~~~~~~~经过测试,如果你想再次使用ir变量,必须重新更新以 下;~~~~~~~~~~~ " );
ir = hashSet.iterator();
while (ir.hasNext())
{
System.out.println(ir.next());
}
}
}
玖--LindedHashSet
具有HashSet的查询速度,且内部使用链表维护元素的顺序(插入的次序)。于是在使用迭代器遍历 Set时,结果会按元素插入的次序显示。
import java.util.Iterator;
import java.util.LinkedHashSet;
public class LinkedHashSetTest {
public static void main(String[] args) {
LinkedHashSet < Integer > lhashSet = new LinkedHashSet < Integer > ();
lhashSet.add( new Integer( " 1 " ));
lhashSet.add( new Integer( " 2 " ));
lhashSet.add( new Integer( " 3 " ));
System.out.println( " ~~~~~~~~~~~~~~~把LinkedHashSet的所有元素复制 到 Object Array中~~~~~~~~~~~~~~~ " );
Object[] objArray = lhashSet.toArray();
for (Object inte: objArray){
System.out.println(inte);
}
System.out.println( " ~~~~~~~~~~~~~~~检查lhashSet中是否存在值为3的元 素~~~~~~~~~~~~~~~ " );
boolean bool = lhashSet.contains( new Integer( " 3 " ));
System.out.println(bool);
System.out.println( " ~~~~~~~~~~~~~~~迭代lhashSet~~~~~~~~~~~~~~~ " );
for (Iterator it = lhashSet.iterator();it.hasNext();){
System.out.println(it.next());
}
}
}
TreeSet: 保持次序的Set,底层为树结构。使用它可以从Set中提取有序的序列,TreeSet 为使用树来进行存储的Set接口提供了一个工具,对象按升序存储.访问和检 索是很快的。在存储了大量的需要进行快速检索的排序信息的情况下,TreeSet 是一个很好的选择。
import java.util.Iterator;
import java.util.TreeSet;
public class TreeSetTest {
@SuppressWarnings( " unchecked " )
public static void main(String[] args)
{
System.out.println( " ~~~~~~~~~~~~~~TreeSet的排序功能~~~~~~~~~~~~~~~ " );
TreeSet ts = new TreeSet();
ts.add( " B " );
ts.add( " C " );
ts.add( " A " );
ts.add( " E " );
ts.add( " F " );
ts.add( " D " );
// 注意如果TreeSet中有重复(一样的)值,TreeSet会把其他相同的排除掉;
ts.add( " A " );
System.out.println(ts);
System.out.println( " ~~~~~~~~~~~~~~TreeSet的迭代~~~~~~~~~~~~~~~ " );
for (Iterator it = ts.iterator();it.hasNext();){
System.out.println(it.next());
}
}
}
下面说一下他们之间的区别
一、Hashtable和HashMap的区别:
① 都属于 Map 接口的类,实现了将惟一键映射到特定的值上。 Hashtable 是Dictionary的子类,HashMap是Map接口的一个实现类;
②Hashtable中的方法是同步的,而HashMap中的方法在缺省情况下是非同步的。即是说,在多线程应用程序中,不用专门的操作 就安全地可以使用Hashtable了;而对于HashMap,则需要额外的同步机
制。但HashMap的同步问题可通过Collections的一个静态方法得到解 决:Map Collections.synchronizedMap(Map m)这个方法返回一个同步的Map,这个Map封装了底层的 HashMap的所有方法,使得底层
的HashMap即使是在多线程的环境中也是安全的。
③ HashMap 类没有分类或者排序。它允许一个 null 键和多个 null 值。 Hashtable 类似于 HashMap ,但是 不允许 null 键和 null 值。它也比 HashMap 慢, 因为它是同步的。
④HashMap被优先选择。
二、ArrayList和LinkedList
① ArrayList 其 实是包装了一个数组 Object[] , 当实例化一个 ArrayList 时, 一个数组也被实例化,当向 ArrayList 中 添加对象是,数组的大小也相应的改变。这样就带来以下有缺点:
快速随即访问 你可以随即访问每个元素而不用考虑性能问题,通过调 用 get(i) 方法来访问下标为 i 的数组元素。
向其中添加对象速度慢 当你创建数组是并不能确定其容量,所以当改 变这个数组时就必须在内存中做很多事情。
操作其中对象的速度慢 当你要想数组中任意两个元素中间添加对象 时,数组需要移动所有后面的对象。
② LinkedList 是通过节点直接彼此连接 来实现的。每一个节点都包 含前一个节点的引用,后一个节点的引用和节点存储的值。当一个新节点插入时,只需要修改其中保持先后关系的节点的引用即可,
当删除记录时也一样。这样就带来以下有缺点:
操作其中对象的速度快 只需要改变连接,新的节点可以 在内存中的任何地方
不能随即访问 虽然存在 get() 方法,但是这个方法是通过遍历接点来定位的所以速度慢。
③当一些被定义好的数据需要放到与数组对应的 List 中, ArrayList 是很好的选择, 因为它可以动态变化,但是不要在整个应用程序用频繁的使用。当你要很方便的操作其中的数据而不用随即访问时
LinkList 是很好的选择。如果你要频繁随即访问建议使用数组。