Java集合详解Collection、Map



        Java Collections FrameworkJava提供的对集合进行定义,操作,和管理的统一的架构。这个集合框架主要由接口、抽象类、实现类构成。

Java的集合有两大接口:CollectionMap

 

Collection接口
  

API解释:Collection是层次结构中的根接口Collection 表示一组对象,这些对象也称为 collection 的元素。一些 collection 允许有重复的元素,而另一些则不允许。一些 collection 是有序的,而另一些则是无序的。JDK 不提供此接口的任何直接 实现:它提供更具体的子接口(如 Set List,这两个是最常用的子接口)实现。此接口通常用来传递 collection,并在需要最大普遍性的地方操作这些 collection

 

       Collection是最基本的集合接口,一个Collection代表一组Object,即Collection的元素(Elements)就是一个对象。

 

       java集合只能保存引用类型的数据,是对象的引用

 

Java SDK不提供直接继承自Collection的类,只提供了子接口,如SetListJava SDK提供的类都是继承自Collection的“子接口”如ListSet

 

       所有通用的 Collection 实现类(通常通过它的一个子接口间接实现 Collection)应该提供两个“标准”构造方法:一个是 void(无参数)构造方法,用于创建空 collection;另一个是带有 Collection 类型单参数的构造方法,用于创建一个具有与其参数相同元素新的 collection。实际上,后者允许用户复制任何 collection,以生成所需实现类型的一个等效 collection。尽管无法强制执行此约定(因为接口不能包含构造方法),但是 Java 平台库中所有通用的 Collection 实现都遵从它。

 

 

 

Collection常见方法:

add(E e);  addAll(Collection c); 

contains(Obj o) ---- 返回是否包含指定的元素(true false)

containsAll(Collection c) ----  返回是否包含c中所有元素

isEmpty();  iterator(); remove();  clear();  size(); toArray();

 

 

     

 

Java集合框架的基本接口/类层次结构:

 

[I]:接口

[C]:类

 

java.util.Collection [I]

+--java.util.List [I]

   +--java.util.ArrayList [C]

   +--java.util.LinkedList [C]

   +--java.util.Vector [C]

      +--java.util.Stack [C]

+--java.util.Set [I]

   +--java.util.HashSet [C]

   +--java.util.SortedSet [I]

      +--java.util.TreeSet [C]

 

java.util.Map [I]

+--java.util.SortedMap [I]

   +--java.util.TreeMap [C]

+--java.util.Hashtable [C]

+--java.util.HashMap [C]

+--java.util.LinkedHashMap [C]

+--java.util.WeakHashMap [C]

 

 

 

 

 

List子接口

1 可以包含重复的元素

2 是一个有序的集合,位置不可以改变,使用此接口能够精确的控制每个元素插入的位置。

3、提供了按索引访问的方式。用户能够使用索引(元素在List中的位置,类似于数组下标)来访问List中的元素,这类似于Java的数组。 

4 、除了具有Collection接口必备的iterator()方法外,List还提供一个listIterator()方法,返回一个ListIterator接口,和标准的Iterator接口相比,ListIterator多了一些add()之类的方法,允许添加,删除,设定元素,还能向前或向后遍历。
  实现List接口的常用类有LinkedListArrayListVectorStack

 

 

LinkedList

 

此外LinkedList提供额外的getremoveinsert方法在 LinkedList的首部或尾部。这些操作使LinkedList可被用作堆栈(stack),队列(queue)或双向队列(deque)。
   
注意LinkedList没有同步方法。如果多个线程同时访问一个List,则必须自己实现访问同步。一种解决方法是在创建List时构造一个同步的List

    List list =Collections.synchronizedList(new LinkedList(...)); 

 

 

 

ArrayList

 

List 接口的大小可变数组的实现。实现了所有可选列表操作,并允许包括null在内的所有元素。

 

每个ArrayList实例都有一个容量(Capacity),即用于存储元素的数组的大小。这个容量可随着不断添加新元素而自动增加,但是增长算法 并没有定义。当需要插入大量元素时,在插入前可以调用ensureCapacity方法来增加ArrayList的容量以提高插入效率。

 

常用方法:add()

 

ArrayList  list = new ArrayList();

List.add(“aaaaa”);

List.add(“bbbbb”);

       //因为是有序的,可以使用for循环输出

       for( ){

              SOP(list);

}

 

 

   利用ArrayListtoArray()返回一个对象的数组;  也可以利用Arrays.asList()方法返回一个列表

Arrays.asList()Collection.toArray()是作为数组和集合类的一个桥

如果想从集合类中获得一个数组可以使用toArray()方法;如果想从数组中获得一个列表可以使用asList()方法

 

import java.util.*;

class Point {

int x, y;

Point(int x, int y) {

   this.x = x;

   this.y = y;

}

public String toString() {

   return "x=" + x +",y=" + y;

}

}

public class ArrayListToArrayTest {

public static void main(String[] args) {

   ArrayList a1 = newArrayList();

   a1.add(new Point(3, 3));

   a1.add(new Point(4, 4));

   a1.add(new Point(5, 5));

 

   for (int i = 0; i <a1.size(); i++) {

   System.out.println(a1.get(i));

   }

   System.out.println(a1);

 

   Object[] objs = a1.toArray();// 利用ArrayListtoArray()返回一个对象的数组.

   for (int i = 0; i <objs.length; i++) {

    System.out.println(objs[i]);

   }

   System.out.println(objs);//

   List l =Arrays.asList(objs);// Arrays.asList()返回一个列表.

   System.out.println(l);

 

}

}

结果:

 

x=3,y=3

x=4,y=4

x=5,y=5

[x=3,y=3, x=4,y=4, x=5,y=5]

x=3,y=3

x=4,y=4

x=5,y=5

[Ljava.lang.Object;@1fc4bec

[x=3,y=3, x=4,y=4, x=5,y=5]

 

 

LinkedList一样,ArrayList也是非同步的(unsynchronized)。

 

 

 

Vector
  Vector非常类似ArrayList,但是Vector是同步的。由Vector创建的Iterator,虽然和 ArrayList创建的Iterator是同一接口,但是,因为Vector是同步的,当一个Iterator被创建而且正在被使用,另一个线程改变了 Vector的状态(例如,添加或删除了一些元素),这时调用Iterator的方法时将抛出 ConcurrentModificationException,因此必须捕获该异常

 

 

 

Stack
  Stack继承自Vector,实现一个后进先出的堆栈。Stack提供5个额外的方法使得Vector得以被当作堆栈使用。基本的pushpop 方法,还有peek方法得到栈顶的元素,empty方法测试堆栈是否为空,search方法检测一个元素在堆栈中的位置。Stack刚创建后是空栈。

 

 

 

 

Set子接口

不可以包含重复的元素。即任意的两个元素e1e2都有e1.equals(e2)=falseSet最多有一个null元素

 

Set是一个无序的集合,但是子接口SorttedSet是一个按照升序进行排列元素的Set

 

很明显,Set的构造函数有一个约束条件,传入的Collection参数不能包含重复的元素。

 

HashSet

        此类实现 Set 接口,由哈希表(实际上是一个 HashMap 实例)支持。它不保证集合的迭代顺序;特别是它不保证该顺序恒久不变。此类允许使用 null 元素。
    HashSet
不是同步的,需要用以下语句来进行S同步转换:
           Set s = Collections.synchronizedSet(new HashSet(...))

 

 

SortedSet

       Set的一个子接口。TreeSet实现了SortedSet

 

 

 

SetList比较:
    Set
:检索元素效率低下,删除和插入效率高,插入和删除不会引起元素位置改变。
    List
:和数组类似,List可以动态增长,查找元素效率高,插入删除元素效率低,因为会引起其他元素位置改变。

 

 

 


比较:

arraylistlinkedlist

1.ArrayList是实现了基于动态数组的数据结构LinkedList基于链表的数据结构。
2.
对于随机访问getsetArrayList觉得优于LinkedList,因为LinkedList要移动指针。
3.
对于新增和删除操作addremoveLinedList比较占优势,因为ArrayList要移动数据。
   
这一点要看实际情况的。若只对单条数据插入或删除,ArrayList的速度反而优于LinkedList。但若是批量随机的插入删除数据,LinkedList的速度大大优于ArrayList. 因为ArrayList每插入一条数据,要移动插入点及之后的所有数据。

 

 

 

 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 

 

Map接口:

       API: 将键映射到值的对象。一个映射不能包含重复的键;每个键最多只能映射一个值。

Map 接口提供三种collection视图(注意:这个collectionCollection是不同的概念,collection表示集合,Collection表示集合下的一个借口Collection),允许以键集、值集合或键-值映射关系集的形式查看某个映射的内容。映射的顺序 定义为迭代器在映射的 collection 视图中返回其元素的顺序。某些映射实现可明确保证其顺序,如 TreeMap 类;某些映射实现则不保证顺序,如 HashMap 类。

 

Map没有继承Collection接口。也就是说MapCollection2种不同的集合。

 

Collection可以看作是(value)的集合,而Map可以看作是(keyvalue)的集合。


     Map
接口由Map的内容提供3种类型的集合视图,一组key集合,一组value集合,或者一组key-value映射关系的集合。

 

一个Map中不能包含相同的key,每个key只能映射一个 value

 

 

 

Map可以出现在kv的映射中,vnull的情况。

       Map集合允许值对象为null,并且没有个数限制,所以当get()方法的返回值为null时,可能有两种情况,一种是在集合中没有该键对象,另一种是该键对象没有映射任何值对象,即值对象为null。因此,在Map集合中不应该利用get()方法来判断是否存在某个键,而应该利用containsKey()方法来判断。

         package com;

import java.util.HashMap;

import java.util.Map;

public class te {

    public static void main(String[] args) { 

         

        Map<String,String> map = new HashMap<String,String>();

        map.put("k", null);    // 向列表中添加数据 

        /**

         * 使用get()判断Map中是否包含某个键值对,会出现判断不准确的情况

         * */

        System.out.println(map.get("kkk"));  //输出结果 null

        System.out.println(map.get("k"));    //输出结果 null

       

        /**

         * 正确的做法是:containsKey()方法来判断

         * */

        map.put("cc", "ggggggggggg"); // 向列表中添加数据 

        boolean contains = map.containsKey("cc");   //返回truefalse

        if (contains) { 

            System.out.println("Map集合中包含键值对"); 

        } else { 

            System.out.println("Map集合中不包含键值对"); 

        } 

   } 

}

 

 

 

操作方法:

可以把这个接口方法分成三组操作:改变、查询和提供可选视图。

 

改变操作允许从映射中添加和除去键-值对。键和值都可以为 null。但是,不能把Map 作为一个键或值添加给自身。

 

Object put(Objectkey, Object value)返回值是被替换的值。

Objectremove(Object key)

void putAll(Mapmapping)

void clear()

查询操作允许您检查映射内容:

 

Object get(Objectkey)

booleancontainsKey(Object key)

booleancontainsValue(Object value)

int size()

boolean isEmpty()

最后一组方法允许您把键或值的组作为集合来处理。

 

public SetkeySet()

public Collectionvalues()

public SetentrySet()

因为映射中键的集合必须是唯一的,您用 Set 支持。因为映射中值的集合可能不唯一,您用Collection 支持。最后一个方法返回一个实现 Map.Entry 接口的元素 Set

 

 

 

Map.Entry 接口

Map entrySet() 方法返回一个实现Map.Entry 接口的对象集合。集合中每个对象都是底层 Map 中一个特定的键-值对。

 

通过这个集合迭代,您可以获得每一条目的键或值并对值进行更改。但是,如果底层 Map Map.Entry 接口的setValue() 方法外部被修改,此条目集就会变得无效,并导致迭代器行为未定义。

 

 

Hashtable

 

       Hashtable 继承自 Dictiionary

       Hashtable实现Map接口,实现一个key-value映射的哈希表。key或者value不允许为空。

Hashtable通过initial capacityload factor两个参数调整性能。通常缺省的load factor 0.75较好地实现了时间和空间的均衡。增大load factor可以节省空间但相应的查找时间将增大,这会影响像getput这样的操作。
使用Hashtable的简单示例如下,将123放到Hashtable中,他们的key分别是”one””two””three”
    Hashtable numbers = new Hashtable();
    numbers.put(“one”, new Integer(1));
    numbers.put(“two”, new Integer(2));
    numbers.put(“three”, new Integer(3));
  要取出一个数,比如2,用相应的key
    Integer n = (Integer)numbers.get(“two”);
    System.out.println(“two = ” + n);

  1. 由于作为key的对象将通过计算其散列函数来确定与之对应的value的位置,因此任何作为key的对象都必须实现hashCodeequals方法。hashCodeequals方法继承自根类Object

 

  1. 如果你用自定义的类当作key的话,要相当小心,按照散列函数的定义,如果两个对象相同,即obj1.equals(obj2)=true,则它们的hashCode必须相同,但如果两个对象不同,则它们的hashCode不一定不同。如 果两个不同对象的hashCode相同,这种现象称为冲突,冲突会导致操作哈希表的时间开销增大,所以尽量定义好的hashCode()方法,能加快哈希 表的操作。

     

3、如果相同的对象有不同的hashCode,对哈希表的操作会出现意想不到的结果(期待的get方法返回null),要避免这种问题,只需要牢记一条:要同时复写equals方法和hashCode方法,而不要只写其中一个。
  Hashtable是同步的。

 

 

HashMap

      

       继承了AbstractMap

       不是同步的Map

允许null,即nullvaluenull key

 

 

 

 

WeakHashMap
  WeakHashMap是一种改进的HashMap,它对key实行弱引用,如果一个key不再被外部所引用,那么该key可以被GC回收。



 

 

相互比较:

 

hashtablehashmap

 

.历史原因:Hashtable是基于陈旧的Dictionary类的,HashMapJava 1.2引进的Map接口的一个实现

.同步性:Hashtable是线程安全的,也就是说是同步的,而HashMap是线程序不安全的,不是同步的

.值:只有HashMap可以让你将空值作为一个表的条目的keyvalue

 

 

HashMapTreeMap

       1  HashMap通过hashcode对其内容进行快速查找,而TreeMap中所有的元素都保持着某种固定的顺序,如果你需要得到一个有序的结果你就应该 使用TreeMapHashMap中元素的排列顺序是不固定的)。集合框架提供两种常规的Map实现:HashMapTreeMap (TreeMap实现SortedMap接口)

       2 Map 中插入、删除和定位元素,HashMap 是最好的选择。但如果您要按自然顺序或自定义顺序遍历键,那么TreeMap会更好。使用HashMap要求添加的键类明确定义了hashCode() equals()的实现。  这个TreeMap没有调优选项,因为该树总处于平衡状态。

 结过研究,二树map一样,但顺序不一样,导致hashCode()不一样。  同样做测试:
     
hashMap中,同样的值的map,顺序不同,equals时,false;
     
而在treeMap中,同样的值的map,顺序不同,equals时,true,说明,treeMapequals()时是整理了顺序了的。

 

 

 

 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 

各种情况下适合使用哪种集合:

       如果涉及到堆栈,队列等操作,应该考虑用List,对于需要快速插入,删除元素,应该使用LinkedList,如果需要快速随机访问元素,应该使用ArrayList
  如果程序在单线程环境中,或者访问仅仅在一个线程中进行,考虑非同步的类,比如HashMap,其效率较高,如果多个线程可能同时操作一个类,应该使用同步的类。

       要特别注意对哈希表的操作,作为key的对象要正确复写equalshashCode方法。
  尽量返回接口而非实际的类型,如返回List而非ArrayList,这样如果以后需要将ArrayList换成LinkedList时,客户端代码不用改变。这就是针对抽象编程

 

 

 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 

如何遍历Collection中的每一个元素?

 

1、增强for循环 for(Objo:c){syso(o)}

     2、使用iterator Iteratorit=c.iterator;

         while(it.hasNext()){Object o = it.next()}

     3、普通循环:for(Iteratorit=c.iterator();it.hasNext();){it.next() }

 

 

       注意:不论Collection的实际类型如何,一般都是实现Collection接口的子接口List或者Set,而生成的实际类型。它都支持一个iterator()的方法,该方法返回一个迭代子,使用该迭代子即可逐一访问Collection中每一个元素。典型的用法如下:
    Iterator it =collection.iterator(); // 获得一个迭代子
    while(it.hasNext()){
      Object obj =it.next(); // 得到下一个元素
    }

 

------------------------------------------------------------------------------------------------------------------------------------------------------------












 归纳总结:

 

接口

简述

实现

操作特性

成员要求

Set

成员不能重复

HashSet

外部无序地遍历成员

成员可为任意Object子类的对象,但如果覆盖了equals方法,同时注意修改hashCode方法。

TreeSet

外部有序地遍历成员;附加实现了SortedSet, 支持子集等要求顺序的操作

成员要求实现caparable接口,或者使用 Comparator构造TreeSet。成员一般为同一类型。

LinkedHashSet

外部按成员的插入顺序遍历成员

成员与HashSet成员类似

List

提供基于索引的对成员的随机访问

ArrayList

提供快速的基于索引的成员访问,对尾部成员的增加和删除支持较好

成员可为任意Object子类的对象

LinkedList

对列表中任何位置的成员的增加和删除支持较好,但对基于索引的成员访问支持性能较差

成员可为任意Object子类的对象

Map

保存键值对成员,基于键找值操作,compareTocompare方法对键排序

HashMap

能满足用户对Map的通用需求

键成员可为任意Object子类的对象,但如果覆盖了equals方法,同时注意修改hashCode方法。

TreeMap

支持对键有序地遍历,使用时建议先用HashMap增加和删除成员,最后从HashMap生成TreeMap;附加实现了SortedMap接口,支持子Map等要求顺序的操作

键成员要求实现caparable接口,或者使用Comparator构造TreeMap。键成员一般为同一类型。

LinkedHashMap

保留键的插入顺序,用equals 方法检查键和值的相等性

成员可为任意Object子类的对象,但如果覆盖了equals方法,同时注意修改hashCode方法。

IdentityHashMap

使用== 来检查键和值的相等性。

成员使用的是严格相等

WeakHashMap

其行为依赖于垃圾回收线程,没有绝对理由则少用

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值