java集合框架总结

来源:互联网 发布:大数据聚类分析 编辑:程序博客网 时间:2024/05/29 07:36

一、java容器类库的简图

先给出一张java容器类库的简图(不包括抽象类和遗留构建),只包含你在一般情况下会碰到的接口和类。

这里写图片描述

你可以看到,其实只有四种容器:Map,List,Set和Queue,它们各有两到三个实现版本(Queue的java.util.concurrent实现没有包括在上面这张图中)。常用的容器用黑色粗线框表示。点线框表示接口,实线框表示普通的(具体的)类。带有空心箭头的点线表示一个特定的类实现了一个接口,实心箭头表示某个类可以生成箭头所指向的类的对象。

二、java容器类库的完备图

下面再给出java容器类库更加完备的图,包括抽象类和遗留构件(不包括Queue的实现)。

这里写图片描述

三、基本概念

java容器类库的用途是“保存对象”,并将其划分为两个不同的概念:

1、Collection

一个独立元素的序列,这些元素都服从一条或多条规则。List必须按照插入的顺序保存元素,而Set不能有重复元素。Queue按照排队规则来确定对象产生的顺序(通常与它们被插入的顺序相同)。

2、Map

一组成对的“键值对”对象,允许你使用键来查找值。ArrayList允许你使用数字来查找值。映射表允许我们使用另一个对象来查找某个对象,它也被称为“关联数组”,因为它将某些对象与另外一些对象关联在了一起;或者被称为“字典”,因为你可以使用键对象来查找值对象。

四、java提供了大量持有对象的方式

(1)数组将数字与对象联系起来。它保存类型明确的对象,查询对象时,不需要对结果做类型转换。它可以是多维的,可以保存基本类型的四。但是,数组一旦生成,其容量就不能改变。

(2)Collection保存单一的元素,而Map保存相关联的键值对。有了java的泛型,你就可以指定容器中存放的对象类型,因此,你就不会将错误类型的对象放置到容器中,并且在从容器中获取元素时,不必进行类型转换。各种Collection和各种Map都可以在你向其中添加更多的元素时,自动调整尺寸。容器不能持有基本类型,但是自动包装机制会仔细执行基本类型到容器中所持有的包装器类型之间的双向转换。

(3)像数组一样,List也建立数字索引与对象的关联,因此,数组和List都是排好序的容器。List能够自动扩充容器。

(4)如果要进行大量的随机访问,就是用ArrayList;如果要经常从表中间插入或删除元素,则应该使用LinkedList。

(5)各种Queue以及栈的行为,由LinkedList提供支持。

(6)Map是一种将对象(而非数字)与对象关联的设计。HashMap设计用来快速访问;而TreeMap保持“键”始终处于排序状态,所以没有HashMap快。LinkedHashMap保持元素插入的顺序,但是也通过散列提供了快速访问能力。

(7)Set不接受重复元素。HashSet提供最快的查询速度,而TreeSet保持元素处于排序状态。LinkedHashSet以插入顺序保存元素。

(8)新程序中不应该使用过时的Vector、HashTable和Stack。

五、Set和存储顺序

当你在创建自己的类型时,要意识到Set需要一种方式来维护存储顺序,而存储顺序如何维护,在Set的不同实现之间会有所变化。因此,不同的Set实现不仅具有不同的行为,而且它们对于在特定的Set中放置的元素类型也有不同的要求。

Set(interface)

存入Set的每个元素都必须是唯一的,因为Set不保存重复元素。加入Set的元素必须定义equals()方法以确保对象的唯一性。Set和Collection有完全一样的接口。Set接口不保证维护元素的次序。

HashSet

为快速查找而设定的Set。存入HashSet的元素必须定义hashCode()。

TreeSet

保持次序的Set,底层为树结构。使用它可以从Set中提取有序的序列。元素必须实现Comparable接口。

LinkedHashSet

具有HashSet的查询速度。且内部使用链表维护元素顺序(插入的次序)。于是在使用迭代器遍历Set时,结果会按元素插入的次序显示。元素也必须定义hashCode()方法。

六、Map

映射表(也称为关联数组)的基本思想是它维护的是键-值(对)关联,因此你可以使用键来查找值。标准的java类库中包含了Map的几种基本实现。

HashMap

Map基于散列表的实现(它实现了HashTable)。插入和查询“键值对”的开销是固定的。可以通过构造器设置容量和负载因子。以调整容器的性能。

LinkedHashMap

类似于HashMap,但是迭代遍历它时,取得“键值对”的顺序是其插入次序,或者是最近最少使用(LRU)的次序。只比HashMap慢一点;而在迭代访问时反而更快,因为它是用链表维护内部结构。

TreeMap

基于红黑树的实现。查看“键”或者“键值对”时,它们会被排序(次序由Comparable或Comparator决定)。TreeMap的特点在于,所得到的结果是经过排序的。TreeMap是唯一的带有subMap()方法的Map,它可以返回一个子树。

WeakHashMap

弱键(weak key)映射,允许释放映射所指向的对象;这是为解决某类特殊问题而设计的。如果映射之外没有引用指向某个“键”,则此“键”可以被垃圾回收器回收。

ConcurrentHashMap

一种线程安全的Map,它不涉及同步加锁。

IdentityHashMap

使用==替代equals()对“键”进行比较的散列映射。专为解决特殊问题而设计。

对Map中使用的键的要求与对Set中的元素的要求一样,任何键都必须具有一个equals()方法;如果键被用于散列Map,那么它必须还具有恰当的hashCode()方法;如果键被用于TreeMap,那么它必须实现Comparable。


有关java集合框架中各接口和类的具体实现方法可以参看以下文章,java集合框架,总结的很详细。


七、有关java集合框架的应用笔试题

以上只是简单的介绍了一下java容器的接口和实现类,下面我们通过几个具体的笔试题来深入了解一下java集合框架的使用。

1、java集合框架的层次结构

Collection接口: 

       Set接口:

            HashSet具体类

            LinkedHashSet具体类

            TreeSet具体类

       List接口: 
            ArrayList具体类

            LinkedList具体类

            向量类Vector具体类

            Stack具体类

Map接口:
       HashMap类

       LinkedHashMap类

       TreeMap类   

2、使用Collection接口定义的公用方法对集合和线性表操作

TestCollection.java

import java.sql.Array;import java.util.ArrayList;import java.util.Arrays;import java.util.Collection;import java.util.Date;import java.util.Iterator;import org.junit.Test;public class TestCollection {    @Test    public void testCollection1(){        Collection coll=new ArrayList();        //1、size();返回集合中元素的个数        System.out.println(coll.size());        //2、add(Object Object);向集合中添加一个元素        coll.add(123);        coll.add("AA");        coll.add(new Date());        coll.add("BB");        System.out.println(coll.size());        //3、addAll(Collection collection);将形参collection中包含的所有元素添加到当前集合中        Collection coll1=Arrays.asList(1,2,3);//把数组添加到集合当中        coll.addAll(coll1);        System.out.println(coll.size());        //查看集合元素        System.out.println(coll);        //4、isEmpty():判断集合是否为空        System.out.println(coll.isEmpty());//一开始coll集合中添加了元素,所以值为false        //5、clear():清空集合元素        coll.clear();        System.out.println();    }    @Test    public void testCollection2(){        Collection coll=new ArrayList();        coll.add(123);        coll.add("AA");        coll.add(new Date());        coll.add("BB");        coll.add(new Person("MM", 23));//①        System.out.println(coll);        //6、contains(Object Object):判断集合中是否包含指定的Object元素。如果包含,返回true,反之返回false        //判断的依据:根据元素所在的类的equals()方法进行判断        //明确:如果存入集合中的元素是自定义的对象。要求:自定义类要重写equals()方法!        boolean b1=coll.contains("678");//判断集合中是否有678,没有所以返回false。        System.out.println(b1);        boolean b2=coll.contains("AA");//判断集合中是否有AA,有所以返回true。        System.out.println(b2);        boolean b3=coll.contains(new Person("MM", 23));        System.out.println(b3);//①要想输出为true,必须在Person类重写地址,否则输出为false        //7、containsAll(Collection collection):判断当前集合中是否包含collection中所有的元素        Collection coll1=new ArrayList();        coll1.add(123);        coll1.add("AA");        boolean b4=coll.containsAll(coll1);//判断coll里面是不是包含coll1的所有元素        System.out.println("#"+b4);        coll1.add(456);        //8、retainAll(Collection collection):求当前集合与collection的共有的元素,返回给当前集合        coll.retainAll(coll1);//找出coll集合与coll1集合中的共有的元素,然后返回给coll,输出共有元素        System.out.println(coll);        //9、remove(Object Object):删除集合中的Object元素。若删除成功,返回true,否则返回false        boolean b5= coll.remove("BB");        System.out.println(b5);        //10、removeAll(Collection collection):从当前集合中删除包含在collection中的元素        coll.removeAll(coll1);//从coll中删除包含在coll1中的元素        System.out.println(coll);        //11、equals(Object Object):判断集合中的所有元素是否完全相同        Collection coll2=new ArrayList();        coll2.add(123);        coll2.add("AA");        System.out.println(coll1.equals(coll2));        //*12、hashCode()        System.out.println(coll.hashCode());        //13、toArray():将集合转化为数组        Object[]obj=coll.toArray();        for (int i = 0; i < obj.length; i++) {            System.out.println(obj[i]);        }        //14、iterator():返回一个Iterator接口实现类的对象,进而实现集合的遍历        Iterator iterator=coll.iterator();        //方式一:不用        System.out.println(iterator.next());        System.out.println(iterator.next());        System.out.println(iterator.next());        //方式二:不用        for (int i = 0; i < coll.size(); i++) {            System.out.println(iterator.next());        }        //方式三:使用        while (iterator.hasNext()) {            System.out.println(iterator.next());        }    }}

Person.java

public class Person {    private String name;    private int age;    public Person() {        super();    }    public Person(String name, int age) {        super();        this.name = name;        this.age = age;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public int getAge() {        return age;    }    public void setAge(int age) {        this.age = age;    }    @Override    public String toString() {        return "Person [name=" + name + ", age=" + age + "]";    }    @Override    public boolean equals(Object obj) {        if (this == obj)            return true;        if (obj == null)            return false;        if (getClass() != obj.getClass())            return false;        Person other = (Person) obj;        if (age != other.age)            return false;        if (name == null) {            if (other.name != null)                return false;        } else if (!name.equals(other.name))            return false;        return true;    }}

3、使用Iterator接口遍历集合

java的Iterator只能单向移动,这个Iterator只能用来:
(1)使用方法iterator()要求容器返回一个Iterator。Iterator将准备好返回容器的第一个元素。
(2)使用next()获得序列的下一个元素。
(3)使用hasNext()检查序列中是否还有元素。
(4)使用remove()将迭代器新近返回的元素删除。

示例代码:

        Collection coll = new ArrayList();        coll.add("Tody");        coll.add("is");        coll.add("Sunday.");        // Output all elements by iterator        Iterator it = coll.iterator();        while(it.hasNext()) {            System.out.print(it.next() + " ");        }

补充:

ListIterator是一个更加强大的Iterator子类型,它只能用于各种List类的访问。尽管Iterator只能向前移动,但是ListIterator可以双向移动。它还可以产生相对于迭代器在列表中指向的当前位置的前一个和后一个元素的索引,并且可以使用set()方法替换它访问过的最后一个元素。你可以通过调用listIterator()方法产生一个指向List开始处的ListIterator,并且还可以通过调用listIterator(n)方法创建一个一开始就指向列表索引为n的元素处的ListIterator。

4、使用JDK的增强for循环替代迭代Iterator进行集合遍历

public static void main(String[] args) {  Map<String, String> map = new HashMap<String, String>();  map.put("1", "value1");  map.put("2", "value2");  map.put("3", "value3");  //第一种:使用foreach  System.out.println("通过Map.keySet遍历key和value:");  for (String key : map.keySet()) {   System.out.println("key= "+ key + " and value= " + map.get(key));  }  //第二种:使用Iterator  System.out.println("通过Map.entrySet使用iterator遍历key和value:");  Iterator<Map.Entry<String, String>> it = map.entrySet().iterator();  while (it.hasNext()) {   Map.Entry<String, String> entry = it.next();   System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());  }  //第三种:使用foreach(推荐,尤其是容量大时)  System.out.println("通过Map.entrySet遍历key和value");  for (Map.Entry<String, String> entry : map.entrySet()) {   System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());  } }

5、熟悉Set接口,了解何时及如何使用HashSet,LinkedHashSet或TreeHashSet来存储元素

6、使用Comparator接口来比较元素

使用Comparable接口和Comparator接口来比较元素

7、熟悉List接口,了解何时以及如何使用ArrayList或者LinkedList来存储元素

8、区分Vector与ArrayList,并了解如何使用Vector和Stack

9、使用JDK1.5的一般类型来简化程序设计

10、理解Collection和Map的区别,知道何时及如何使用HashMap,LinkedHashMap,TreeHashMap来存储

11、使用Collections类中的静态方法

Collections类中的静态方法:

1.排序: Collections.sort()

(1)自然排序(被排序对象实现compareTo接口)
(2)实现比较器(Comparator)接口对象。

2.取最大值和最小值Collections.max()、Collections.min()。

3.在已排序的List中搜索指定元素:Collections.binarySearch()。

12、使用Arrays类中的静态方法

(1)、sort()

默认由小到大排序,不只对于数值型的可以排序,对于字符串等也都可以进行排序

(2)、binarySearch()

对已排序(从小到大排序的)的数组进行二元搜索,如果找到指定的值就返回其所在的索引位置,否则返回负值

(3)、fill()

将数组的元素全部设定为指定的值

(4)、equals()

比较两个数组元素中的元素值是否全部相等,如果是返回true,否则返回false,适用于一维数组,多维数组用deepEquals()用法同equals;

(5)、deepEquals()

对多维数组进行比较其内容是否一致,不能用于一维数组,会编译不过。

(6)、toString(int[] a)

返回指定数组内容的字符串表示形式。

(7)、copyOf(int[] original, int newLength)

复制指定的数组,截取或用 0 填充(如有必要),以使副本具有指定的长度。

(8)、copyOfRange(int[] original, int from, int to)

将指定数组的指定范围复制到一个新数组。

(9)、asList(array)

利用Arrays.asList(array)将返回一个List,然而这个返回的List并不支持add和remove的操作。返回的List进行添加或删除时将会报 java.lang.UnsupportedOperationException 异常。

原因:在Arrays.asList中,该方法接受一个变长参数,一般可看做数组参数,但是因为基本数据类型,如int[] 本身就是一个类型,所以data变量作为参数传递时,编译器认为只传了一个变量,这个变量的类型是int数组,所以size为1。

因为是arrays.aslist中,看代码可以看到这里返回的ArrayList不是原来的传统意义上的java.util.arraylist了,而是自己工具类的一个静态私有内部类,并没有提供add方法,要自己实现,所以这里是出错了,因此,除非确信array.aslist后长度不会增加,否则谨慎使用:List abc=Arrays.asList(“a”,”b”,”c”),因为这样的长度是无法再add的了


容器类库对于面向对象语言来说是最重要的类库,大多数编程工作对容器的使用比对其他类库中的构件都要多,以上只是对java容器类库的一个简单的总结,相信还有更多深层次的应用等待我去实践,去发掘。

0 0