1111111111111111

08_集合概述

1. 集合框架体系概述

     为什么出现集合类?

          面向对象语言对事物的体现都是以对象的形式,为方便对             

          多个对象的操作,就对对象进行存储,集合就是存储对象最

          常用的一种方法.

     数组和集合类同时容器,有何不可?

          数组虽然也可存储对象,但长度固定; 而集合长度可变

          数组是存储同一类型基本数据类型,集合能存储任意对象

     集合类的特点

          集合只用于存储对象,集合长度是可变的,集合可以存储不同类型的对象.   


图1: 集合框架图

wKiom1P9-kKwGyUmAAHKTDS-Q_Y135.jpg

 

图2: Java框架构成关系图

wKioL1P9-3rjTnSPAAHdGd281Xk601.jpg

 每个容器对数据的存储方式不同,这种存储方式称为数据结构.


2. 集合框架共性方法

        //发现java中对方法的学习用增删查改不能很好的概括,增,删,改可以,但查可以分为判断和获取.这样就五种操作了.增,删,判,获(查),改.

        //集合存储的都是对象的引用(地址)

     boolean add(E e)添加指定的元素(可选操作)

     boolean addAll(Collection<? extends E> c) 将指定 collection 中的所有元素都添加到此 collection 中(可选操作)。

     clear(): 清空集合中所有元素

     boolean contains(Object o) 是否包含指定元素

     boolean containsAll(Collection<?> c) 只判断参数中的集合是否都包含在A集合内,最终A集合没有任何变化.

     boolean isEmpty() 判断是否为空

     boolean remove(Object o)   移除单个实例

     boolean removeAll(Collection<?> c)  取差集

     boolean retainAll(Collection<?> c)  取交集

     int size():返回collection中的元素.

     Object[] toArray() 这个可以理解

     <T> T[]  toArray(T[] a)  应这么写String[] y =  c.toArray(new String[collection.size()])较好

     重点讲讲用于查找的Iterator迭代器接口

          Iterator it = al.iterator(); /*实际上是集合类在List和Set都包含的iterator方法,返回Iterator对象,具体实现方式是内部类.可以认为是继承了AbstractList,实现了Iterable接口.把取出方式定义成内部类,每个容器的数据结构不同,取出的动作细节也不一样.但是都用共性的判断和取出,可以将共性方法抽取.对外提供了Iterator方法.*/

     迭代器使用

     while(it.hasNext()){

          System.out.println(it.next());

     }

     老外为了节省空间,写成这样

     for(Iterator it = al.iterator();it.hasNext(); ){

          System.out.println(it.next());

     }


3. List序列共性方法(List也被成为序列, 它的对象的元素有序可重复,正因为有序,所以操作角标的方法都是该体系特有的方法)

      增 void add(int index, E element) 在列表的指定位置插入指定元素(可选操作)。  

      删 E remove(int index)   移除列表中指定位置的元素(可选操作)。

      查 ListIterator<E> listIterator()  返回此列表元素的列表迭代器(按适当顺序)。

      改 E set(int index, E element)   用指定元素替换列表中指定位置的元素(可选操作)。

      获取 E get(int index)  返回列表中指定位置的元素。       

        list因此多了一种取出所有元素的方法: 

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

                 输出al.get(i); 

            } 

      获取<E> subList(int fromIndex, int toIndex)  返回列表中指定的 fromIndex(包括)和 toIndex(不包括)之间的部分视图。      

     List有自己更强功能的的ListIterator是Iterator的子接口,是带下标的.

     集合引用和迭代器引用在同时操作元素,通过集合获取到对应的迭代器后,在迭代中,进行集合引用的元素添加,迭代器并不知道,所以会出现ConcurrentModificationException异常情况。ListIterator列表迭代器接口具备了对元素的增、删、改、查的动作。

          原 查 next() 但是 增加了previous()

          原 删 void remove() 

          增加了特有了 

            增void add(E e)  

            改 void set(E e) 

            和独有的int nextIndex(), int previousIndex() 和 int nextIndex()


4. List集合的三个常见子类对象(List有序可重复,因为体系有索引)

     ArrayList: 底层使用数组结构, 查询块,增删稍慢. 线程不同步,JDK1.2以上

     LinkedList: 底层是链表结构, 增删块,查询稍慢,JDK1.2以上

     Vector: 底层使用数组结构, 查询块,增删慢. 线程同步.被ArrayList替代了1.0时代产物. 枚举就是Vector特有的取出方式.


     ArrayList详解:拥有角标的方法是其特有方法

         可变长度数组的原理 :当元素超出数组长度,会产生一个新数组,将原数组的数据复制到新数组中,再将新的元素添加到新数组中。

      ArrayList:是按照原数组的 50%延长构造一个初始容量为10的空列表。

      Vector:是按照原数组的 100%延长    


     LinkedList详解:特有的add,get,remove方法  

    在1.6后新方法

           boolean offerFirst(E e) 

               在此列表的开头插入指定的元素。 

           boolean offerLast(E e) 

               在此列表末尾插入指定的元素。 

           E peek() 

          获取但不移除此列表的头(第一个元素)。 

           E peekFirst() 

               获取但不移除此列表的第一个元素;如果此列表为空,则返回 null。 

           E peekLast() 

          获取但不移除此列表的最后一个元素;如果此列表为空,则返回 null。 

           E pollFirst() 

               获取并移除此列表的第一个元素;如果此列表为空,则返回 null。 

           E pollLast() 

               获取并移除此列表的最后一个元素;如果此列表为空,则返回 null。  


     Vector详解

          枚举是Vector特有的取出方式hasMoreElements()和nextElement()方法,发现枚举和迭代器很像.其实枚举和迭代一样的.

          但迭代取代了枚举,不仅是名字更短一点, 还包含可移除的操作, 使用范围也更广.

          推荐使用迭代,而不是枚举.         


1
2
3
4
5
6
7
8
9
10
11
//ArrayList练习一: 去除ArrayList中的重复元素
//思路:新建一个容器,如果新容器没有就存进去,最后返回即可.
public static ArrayList singleElement(ArrayList al){
    ArrayList newAl = new ArrayList();
    for(Iterator it = al.iterator();it.hasNext();){
        Object next = it.next();
        if(!newAl.contains(next))
            newAl.add(next);
    }
    return newAl;
}

//注意:使用iterator.next()取出时每次只取出一个,而不是取出多个.会造成NoSuchElementException

1
2
3
4
5
6
7
8
9
10
11
12
13
//ArrayList练习二:将自定义对象作为元素存到ArrayList集合中,并取出重复元素. 比如:存人对象,同姓名同年龄视为同一个人,为重复元素.
//思路:1.对人描述,封装成对象 2.定义容器,将人存入 3.取出重复元素 4.取出
        //主要第三部分,如何去除重复元素
    public static List singleElement(List list){
        List newList = new ArrayList();
        for(Iterator it = list.iterator();it.hasNext();){
            Person p = it.next();
            if(!newList.contains(p))
                newList.add(p);
        }
        return newList;
    }
//总结:本来是使用void,虽说引用是实际参数地址的拷贝,对拷贝的操作会牵扯到原来的数据,但是不能整个集合赋值给新的引用参数的地址,这是无效的,所以必须有返回值才行.

总结: 在List下的ArrayList和LinkedList的contains和remove方法都是使用了了obj的equals方法.可以自己重写equals方法判断集合内两对象是否"一致".


5. Set集合的两个常见子类对象(Set集合的方法和Collection是一模一样,所以不用多讲)

     元素是无序,不可重复的     

     HashSet(线程是不同步)

          底层数据结构是哈希表,线程非同步.

          通过hasHashCode()和equals()来完成

          如果元素的HashCode相同,才会判断equals是否为true

          如果元素的HashCode不同,不会调用equals,直接是不等.     

     注意,对于判断元素是否存在,以及删除等操作,依赖方法都是hashcode和equals方法. 在使用HashSet,一定要按需覆盖int hashCode()和boolean equals (Object obj)方法.按照优先级判断元素是否能添加删除.

     TreeSet(可以对Set集合中的元素进行排序)

          底层数据结构是二叉树

          通过int compareTo()来完成增,删,查          

          TreeSet排序

               第一种方式:实现Comparable接口,覆盖int compareTo()方法,让元素自身具备比较性

               第二种方式:构造实现Compare接口,覆盖int compare(Object o1, Object o2)方法,将比较器对象作为参数传递给TreeSet集合的构造函数.


6. Map集合的三个常见子类对象

     将键映射到值的对象,一对一对往里存,而且要保证键的唯一性.

          添加

               put(K key, V value)

               putAll(Map<? extends K, ? extends V> m)

          删除

               clear()

               remove(Object key)

          判断

               containsKey(Object key)

               containsValue(Object value)

               isEmpty()

          获取

               get(Object key)

               size()

               values()

               entrySet()

               keySet()

---HashTable: 底层是哈希表,不允许空键空值,线程同步,jdk1.0,效率低

---HashMap: 底层是哈希表,允许空键空值,线程不同步,jdk1.2,效率高

---TreeMap: 底层是二叉树,线程不同步,jdk1.2

Map和Set很像,其实Set底层就是使用了Map集合.


Map集合的共性方法注意

     1.添加元素,如果出现相同的键,那么后添加的值会覆盖原有键对应的值, put方法会会返回被覆盖的值

     2.可通过get方法的返回值来判断一个键是否存在,通过返回null判断.

     3.获取map集合中所有的值

两个重要的获取方法:  keySet()和entrySet()

     1.通过keyset()获取key的Set集合,然后Iterator获取key,最终get(Object key) 获取.

     2.通过entryset()获取关系,然后Iterator获取键值对,最终Map.Entry的getKey和getValue方法获取. 

其实Map.Entry也是一个接口,它是Map接口中的一个内部接口


练习一:使用HashMap

     每个学生都有归属地

     学生Student,地址addr

     学生属性:姓名和年龄,注意姓名和年龄相同视为同一个学生,需保证学生的唯一性

     我的主要代码

wKiom1P9-paQnbfSAAJdj0nggJ8450.jpg

练习二: 对学生对象的年龄进行升序排序  (使用TreeMap即可)

练习三: "sdfkgjlsk"获取该字符串中字母出现的次数


Map扩展: 无非就是集合套集合,用keyset()对于这种复杂的结构似乎简化了操作,但不管怎样还是利于理解的.比使用entryset要简便.

posted @ 2014-09-25 12:12  acc8226  阅读(231)  评论(0编辑  收藏  举报