笔记:集合

Java集合类库将接口(interface)和实现(implementation)分离,首先对集合接口进行说明。

  1. 集合接口

    集合类的基本接口是 Collection 接口,该接口有两个基本方法:

            public interface Collection<E>{

                boolean add(E element);

                Iterator<E> iterator();

                …

            }

    add方法用于向集合增加元素,如果增加元素改变了集合则返回 true,集合没有发生变化则返回false;iterator方法用于返回一个实现类 Iterator 接口的对象,这个迭代器对象依次访问集合中的元素,接口定义如下:

            public interface Iterator<E>{

                E next();

                boolean hasNext();

                void remove();

            }

    next方法用于逐个访问集合的元素,如果到达集合末尾则会抛出 NoSuchElementException 异常,因此需要通过 hasNext方法来判断是否还有元素,也可以使用 for(String ele : iterator) 来循环访问元素;remove方法将删除上次调用next方法时返回的元素,如果需要删除指定位置的元素,需要越过这个元素。

    对于链表,Java集合库增加了ListIterator接口,该接口是 Iterator 的子接口,这个接口额外增加了反向遍历的previous hasPrevious 方法,还增加了 add 方法,这个add方法不反回boolean类型的值,他假定添加操作总会改变链表,接口定义如下:

    public interface ListIterator<E> extends Iterator<E> {

            boolean hasNext();

            E next();

            boolean hasPrevious();

            E previous();

            int nextIndex();

            int previousIndex();

            void remove();

            void set(E e);

            void add(E e);

    }

    如果某个迭代器修改集合时,另一个迭代器对其进行遍历,一定会出现混乱的情况,例如,一个迭代器指向另一个迭代器刚刚删除的元素前面,现在这个迭代器就是无效的,并且不应该被使用,如果迭代器发现他的集合时被另一个迭代器修改了,或者集合本身被修改了,就会抛出一个 ConcurrentModificationException 异常。

  2. 队列(queue)

    队列接口是指可以在队列的尾部增加元素,在队列的头部删除元素,并且可以查找队列中的元素个数,如果需要按照先进先出的规则检索对象,就应该使用队列,队列的接口定义如下:

            interface Queue<E> extends Collection<E> {

                boolean add(E element);

                E remove();

    E poll();

                int size();

    E element();

    E peek();

            }

    实现队列的数据结构类有 ArrayDeque(循环数组队列)、LinkedList(链表队列)和 PriorityQueue(优先级队列)

  • PriorityQueue(优先级队列)

    优先级队列中地元素可以按照任意地顺序插入,却总是按照排序地顺序进行检索,也就是所无论何时调用 remove方法,总会获得当前优先级队列中最小地元素,优先级队列并没有对所有地元素进行排序,而是使用迭代地方式处理,优先级队列使用堆(heap)数据结构,堆是一个可以自我调整地二叉树,对数执行添加和删除操作,可以让最小地元素移动到根,而不必花费时间对元素进行排序。

    • 对象比较

      PriorityQueue使用Comparable接口来比较对象进行排序地,接口定义如下:

                  public interface Comparable<T>{

                      int compareTo(T other);

                  }

      如果a和b相等,调用 a.compareTo(b)一定返回0;如果排序后a位于b之前,则返回负值;如果a位于b之后,则返回正值。

      除了实现 Comparable接口外,还可以将 Comparator 接口对象传递给 PriorityQueue构造器来告诉树集使用不同地比较方法,Comparator接口定义如下:

                  public interface Comparator<T>{

                      int compare(T a,T b);

                  }

      compare方法和 compareTo方法地含义一样

  1. 链表(LinkedList)

    链表是将每个对象存放在独立的节点中,每个节点存放着指向序列中下一个节点的引用,在Java集合库中所有的链表实际上都是双向链表结构,每个节点存放着向前和下一个节点的引用,链表的接口定义如下:

            interface List<E> extends Collection<E>{

                boolean add(E element);

    void add(int index, E element);

                boolean remove(Object obj);

                E remove(int index);

                int size();

                ListIterator<E> listIterator();

                …

            }

    链表是有序集合,add方法是将元素增加到链表的尾部,如果需要将元素增加到链表的中间,可以使用add的带index的重载。

    实现链表的数据结构类有 ArrayList(数组链表)、LinkedList(双向链表)

  2. 散列集(Hashtable)

    散列集可以快速地查找需要地对象,散列表为每个对象计算一个整数,称为散列码,散列码时由对象地实例域产生地一个整数,是通过对象地 hashCode 方法产生地,如果是自定义类就需要负责实现类地 hashCode方法,并且还需要与 equals 方法兼容,即如果a.equals(b)为true,则a与b必须具有相同地散列码。

    实现散列集地数据结构类由 HashSet(散列集合)、HashMap(散列映射)

  3. 树集(TreeSet)

    TreeSet类与散列集类似,不过,树集比散列集有所改进,树集是一个有序集合,可以任意顺序将元素插入集合,在对集合进行遍历时,每个值将自动地按照排序后地顺序呈现,TreeSet类排序是使用树结构完成地,具体实现是红黑树,每次将元素添加到树中时,都被放置在正确地排序位置,因此,将元素添加到树中要比添加到散列表中慢。

  • 对象比较

    TreeSet使用Comparable接口来比较对象进行排序地,接口定义如下:

                public interface Comparable<T>{

                    int compareTo(T other);

                }

    如果a和b相等,调用 a.compareTo(b)一定返回0;如果排序后a位于b之前,则返回负值;如果a位于b之后,则返回正值。

    除了实现 Comparable接口外,还可以将 Comparator 接口对象传递给 TreeSet构造器来告诉树集使用不同地比较方法,Comparator接口定义如下:

                public interface Comparator<T>{

                    int compare(T a,T b);

                }

    compare方法和 compareTo方法地含义一样。

  1. 映射表(Map)

    映射表数据结构用来存储键/值对,如果提供了键,就能够查询到值,键必须是唯一地,不能对同一个键存放多个值,如果对同一个键两次调用put方法,第二个值会替换第一个值,put会返回用这个键参数存储地上一个值,映射表地接口定义如下:

            public interface Map<K,V>{

                int size();

                V get(Object key);

                V put(K key, V value);

                V remove(Object key);

                …

            }

    实现映射表数据结构地类有HashMap(散列映射)、TreeMap(二叉搜索树映射),散列映射表对键进行散列,树映射表用键的整体顺序对元素进行排序,并将其组织成搜索二叉树。

  2. 枚举集(EnumSet)和枚举映射表(EnumMap)

    枚举集是一个枚举类型元素集的高效实现,由于枚举类型只有有限个实例,所以EnumSet内部用位序列实现,如果对应的值在集合中,则相应的位被置为1,EnumSet没有构造函数,使用静态工厂来创建实例,示例代码如下:

    public enum Weekday {

        MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY,SATURDAY,SUNDAY

    }

            EnumSet<Weekday> weekdays = EnumSet.allOf(Weekday.class);

            for (Weekday w : weekdays) {

                System.out.println("EnumValue=" + w);

            }

    枚举映射表是一个键类型为枚举类型的映射表,可以直接且高效的用一个值数组实现,在使用时,需要在构造器中指定键类型,示例代码如下:

            EnumMap<Weekday, Integer> emEnumMap = new EnumMap<Weekday, Integer>(Weekday.class);

            emEnumMap.put(Weekday.FRIDAY, 23);

            emEnumMap.put(Weekday.MONDAY, 233);

            emEnumMap.put(Weekday.SATURDAY, 123);

            emEnumMap.put(Weekday.SUNDAY, 2323);

            emEnumMap.put(Weekday.WEDNESDAY, 21233);

       

            Set<Map.Entry<Weekday, Integer>> set = emEnumMap.entrySet();

            for (Map.Entry<Weekday, Integer> item : set) {

                System.out.println("Key=" + item.getKey() + "\tValue=" + item.getValue());

            }

  3. 同步视图

    如果由多个线程访问集合,就必须保证集合不会被意外破坏,类库的设计者,使用视图机制来确保常规集合的线程安全,而不是使用线程安全的集合类,例如,Collections类的静态synchronizedMap方法可以键任何一个映射表转换成具有同步访问方法的Map,示例代码如下:

    Map<String,Integer> syncMap = Collections.synchronizedMap(new HashMap<String, Integer>());

            List<String> syncList = Collections.synchronizedList(new LinkedList<String>());

  4. 集合与数组之间的转换

    如果有一个数组需要转换为集合,Arrays.asList 的包装器就可以实现这个目的,示例代码如下:

            String[] values=…;

            HashSet<String> staff = new HashSet<>(Arrays.asList(values));

    如果需要将集合转换为数组可以使用toArray方法,该方法有二个重载,第一个重载是返回 Object数组,无法改变类型;第二个重载是返回希望的元素类型的数组,示例代码如下:

            // 返回 Object 类型数组

            Object[] objValues = staff.toArray();

            // 返回 String 类型的数组

            String[] StrValues = staff.toArray(new String[0]);

posted @ 2017-04-25 22:17  立3807  阅读(169)  评论(0编辑  收藏  举报