zoukankan      html  css  js  c++  java
  • 笔记:集合

    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() + " Value=" + 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]);

  • 相关阅读:
    安装oh-my-zsh
    Ubuntu下安装2017版QQ
    Ubuntu安装Git
    链接libtorrent库时出现的问题
    ubuntu 下重装mysql若干问题
    最简单的epoll的使用范例 : 监听 标准输入 ,并将数据回显到终端
    [转]Linux下CodeBlocks的交叉编译
    各种免费素材下载站点
    Qt5:图片彩色键控,设置图片中指定颜色的像素为透明
    C++:预处理指令
  • 原文地址:https://www.cnblogs.com/li3807/p/6764953.html
Copyright © 2011-2022 走看看