• Java_集合框架



    编程时,常常需要集中存放多个数据。可以使用数组来保存,但一旦初始化时指定了数组的长度,数组就不可变了。而集合类就很好的解决了这一问题。Java集合大致可分为 Set、List、Queue、Map四种体系。Java集合框架图:

    【简图】

    • Set 不可重复集合 {HashSet, TreeSet}
    • List 有序,重复集合 {ArrayList, LinkedList, Vector}
    • Map 具有映射关系 key-value集合 {HashMap, TreeMap, HashTable}
    • Queue、Deue 队列集合 {PriorityQueue, ArrayDeue}

    注:顺序分为 自然排序[a-z], 添加元素的排序

    一、Collection 和 迭代器

    Collection接口是 List、Set和 Queue 接口的父接口

    • 迭代器 Iterator 和 Enumeration

    迭代器: Enumeration<E> 接口被 Iterator <E>替代。它的实现类StringTokenizer

    Enumeration e  = new StringTokenizer("A-B-C","-");
    while(e.hasMoreElements()){ // 是否还有元素
    	System.out.println(e.nextElement());  //返回下一个元素
    }
    
    // Arrays.asList(T...a)返回的是一个T List<T> 类型的new ArrayList<>(a)对象
    // 这个ArrayList<E> 是定义在Arrays中的私有类部类,且有一个带 E[] a 参数
    Collection c = Arrays.asList("a","n","b");
    Iterator it = c.iterator();
    for( ;it.hasNext();)
        System.out.println(it.next());
    
    • ListIterator 接口
      • 允许双向遍历list
      • 在遍历时修改List元素
      • 遍历时获取迭代器当前游标所在位置
    List l = Arrays.asList("a","n","b");
    ListIterator lit = l.listIterator();
    while(lit.hasNext()){
        System.out.println(lit.next());
    }
    while(lit.hasPrevious()){
        System.out.println(lit.previous());
    }
    // foreach 是通过迭代器来实现
    for (Object aL : l) {
        System.out.println(aL);
    }
    
    

    二、List 接口与实现类

    • List
      List是一个有序可重复的集合,常用的List实现类 ArrayList, LinkedList和Vector。List接口实现类在实现插入元素时,都会根据索引进行排列,会改变其他元素的位置。

    • AbstractList
      继承 AbstractCollection 抽象类,实现了 List 接口 ,是 ArrayList 和 AbstractSequentiaList 的父类。AbstractList 内部已经提供了 Iterator, ListIterator 迭代器的实现类Itr ,ListItr。

    • ArrayList、LinkedList、Vector

    1-- ArrayList 使用数组方式存储数据(本质上是一个数组),y有初始容量大小 ,超容时自动扩容为原来的1.5倍。线程是不安全的。增删效率低,查询效率高。
    防止不同步访问列表:List list = Collections.synchronizedList(new ArrayList(...));

    ArrayList<String> al = new ArrayList<String>(5); //指定容量大小
    al.ensureCapacity(10); // 增加容量
    al.add("Hello"); // 元素可重复
    al.add("Hello");
    al.add("word");
    al.set(1, "Two"); // 替换索引为1 的元素
    al.add("four");
    al.trimToSize();
    al.remove(3); // 删除索引为 3 的元素
    System.out.println(al.toArray().length);
    System.out.println(al.size()); //3 元素个数
    System.out.println(al.get(1)); //Two 获取 index=0 的元素
    //System.out.println(al.get(3)); // index=3 的元素被删除,报错
    

    2-- LinkedList双向链表,实现了List和 Deque接口。与ArrayList一样也是线程不安全。双向链表,不存在元素限制,没有扩容机制。其查询效率差,增删效率高。

    LinkedList<String> ll = new LinkedList<String>();
    ll.add("adb"); // 元素可重复
    ll.add("adb");
    ll.add(1," ");  // 内部通过遍历删除ll.remove(" ");
    ll.add("shell");
    ll.addFirst("<"); // 列表开头插入指定的元素 对应的删除 ll.removeFirst();
    ll.addLast(">"); // 列表结尾插入指定的元素  对应的删除 ll.removeLast();
    ll.remove(3); // 删除 index=3 的元素
    for(Object l: ll){
        System.out.print(l); // <adb shell> 遍历输出列表元素
        // ll.listIterator(); // 正向迭代
        //ll.descendingIterator(); // 反向迭代
    }
    ll.push("shell"); //实质上就是将元素插入到开头位置 addFirst()
    System.out.println("
    "+ll.get(0)); // 内部通过遍历查找 index=0 的元素 或者 ll.getFirst();
    System.out.println(ll.element()); // 内部调用 getFirst()
    System.out.println(ll.pop()); // 内部调用 removeFirst()
    ll.clear(); // 清除列表所有元素
    

    3-- Vector类实现了可扩展的对象数组,与ArrayList一样有初始容量大小,超容会自动扩容为原来的2倍,但线程是安全的。所以增删查询效率比ArrayList差一些。

    Vector<Integer> v = new Vector<Integer>();
    // Vector 继承AbstractCollection 重写的 toString() 方法
    System.out.println(v); // 打印[] 与 ArrayList 一样
    v.add(1);
    v.addElement(2);
    v.insertElementAt(129, 1);
    for(Object o: v)
        System.out.println(o); // 1 
     129 
     4 迭代 Vector 中的元素
    //v.setSize(19);// 设置元素个数的大小
    //System.out.println(v.capacity()); // 20
    v.trimToSize();  //将容量大小变为所包含元素个数大小
    System.out.println(v.capacity()); // 3   当前列表的容量大小
    v.clear();
    if(v.isEmpty()) System.out.println("none ");
    

    三、Map 接口与实现类

    • Map 接口
      Map将键映射到值的对象,不能包含重复的键。Map 中元素的顺序取决于迭代器迭代时的顺序,有的实现类(TreeMap)保证了元素输入输出时的顺序,有的实现类(HashMap)则是无序的 .

    • AbstractMap 抽象类
      AbstractMap 提供了 Map 的基本实现。该抽象类中只有一个抽象方法public abstract Set<Entry<K,V>> entrySet();

    • HashMap、TreeMap、 HashTable

    1-- HashMap 采用哈希表实现的键值对集合,底层实现链表数组(jdk1.8加入红黑树).有默认初始容量,扩容由容量和加载因子(0.75)决定。非线程安全的。

    HashMap<String, String> m = new HashMap<String, String>();
    m.put("1","zzz"); // key不能重复,value可以
    m.put("2","zzz");
    m.put("0","");
    m.put(null,"111"); // 不打印该键值,被最后为null的键覆盖
    m.put("4",null);
    m.put(null,null); // key,value允许空值
    Set<String> s =m.keySet();
    for(Object o: s){ // 迭代输出 map中的 keys
        System.out.println("key:" + o);
    }
    Collection c = m.values();
    for(Object o: c){ // 迭代输出 map中的 values
        System.out.println("value:" + o);
    }
    // 迭代map
    for(Map.Entry<String, String> entry: m.entrySet()){
        System.out.println(entry.getKey()+"--->"+entry.getValue());
    }
    

    2-- TreeMap 基于红黑树实现,按自然顺序或自定义顺序遍历键(key),键不能为null, 非线程安全

    TreeMap<String, String> tm = new TreeMap<String, String>();
    tm.put("1","22");
    //tm.put(null,null); // 键不能为null, 会抛出空指针异常
    tm.put("","");
    tm.put("2",null);
    tm.put("0","22");
    System.out.println(tm.replace("","1"));// 替换对应key的值
    for(Map.Entry<String, String> entry: tm.entrySet()){
        System.out.println(entry.getKey()+"--->"+entry.getValue());
    }
    System.out.println("value:"+tm.get("")); // 通过key获取 value
    System.out.println("first key:" +tm.firstKey() +" ,value:"+ tm.lastKey()); // 获取第一个key - value
    System.out.println(tm.higherKey("2")); //大于给定键的小键,不存在则返回 null
    System.out.println(tm.tailMap("0")); // 返回其键大于等于 key的键值
    System.out.println(tm.ceilingKey("2")); //大于或等于给定键的键
    System.out.println(tm.lowerKey("2")); // 小于给定键的最大键,如果没有则返回 nul
    

    3-- HashTable是散列表,继承Dictionary抽象类直接实现了Map接口。键和值都不能为 null,线程安全

    Hashtable<String, String> ht = new Hashtable<String, String>();
     ht.put("","");
     //ht.put(null,"");  // 键不能为 null
     //ht.put("1",null); // 值也不能为 null
     ht.put("1","a");
     ht.put("2","b");
     ht.put("0","c");
     ht.put("3","d");
     Enumeration e = ht.elements();//可以使用Enumeration 迭代器
     for(Map.Entry<String, String> entry: ht.entrySet()){
         System.out.println(entry.getKey()+"--->"+entry.getValue());
     }
    

    四、Set 接口与实现类

    • Set 接口
      Set是一个不可重复的集合,允许包含值为null的元素。

    • AbstractSet 抽象类
      继承 AbstractCollection 抽象类,实现了 Set 接口。与AbstractList 不同,AbstractSet类中只有3 个方法 equals、hashCode、removeAll。其add,remove,clear ... 都是子类自己实现。

    • HashSet、TreeSet

    1-- HashSet继承AbstractSet抽象类,直接实现了Set接口。无序列集合,并且多线程不安全。底层通过HashMap实现,Map中key不能重复,这也就是Set不允许重复的原因。

    HashSet<String> hs = new HashSet<String>();
    String str = new String("abc");
    hs.add(null);
    hs.add("abc");
    hs.add(str); // 重复元素
    hs.add("");
    System.out.println(hs.size()); // 3 元素个数
    // forEach 内部通过 for(T t:this){} 实现,调用的是Iterable接口(即 Collection接口的父类)中的方法,
    hs.forEach(System.out::println); // 等同于 o -> System.out.println(o)
    hs.removeAll(hs); // 调用父类的方法删除所有元素
    hs.addAll(Arrays.asList("a","a","b")); // 将指定集合中的所有元素添加到此集合,可用于去重
    

    2-- TreeSet继承AbstractSet抽象类,实现NavigableSet接口,而该接口继承了SortedSet最后才继承Set接口。使用元素的自然顺序对元素进行排序,或者根据创建 set 时提供的 Comparator 进行排序,具体取决于使用的构造方法。

    TreeSet<String> ts = new TreeSet<String>();
    ts.add("aaa0"); // 迭代时,按自然排序输出 [1, 2, 3, 4, aaa, aaa0, begin, end]
    ts.add("aaa");
    ts.add("begin");
    ts.add("1");
    ts.add("2");
    ts.add("3");
    ts.add("4");
    ts.add("end");
    for(Object o: ts)
        System.out.println(o);
    System.out.println("
    "+ts.first()); // 1  返回集合中第一个元素  返回最后元素:ts.last()
    System.out.println(ts.subSet("a","b")); // [aaa, aaa0] 返回范围内部分元素
    System.out.println(ts.tailSet("0")); // 返回大于或等于某元素的所有元素
    System.out.println(ts.headSet("3")); // 返回小于某元素的所有元素
    

    五、Queue 接口与实现类

    • Queue接口
      Queue 继承自 Collection 接口 ,Deque, LinkedList, PriorityQueue, BlockingQueue 等类都实现了它。队列通常但不一定是以FIFO(先进先出)方式排序元素。

    • Deque接口
      双向队列(Deque),是Queue的一个子接口,双向队列是指该队列两端的元素既能入队(offer)也能出队(poll).它的实现类:ArrayDeque。

    • PriorityQueue、ArrayDeque

    1-- PriorityQueue继承AbstractQueue抽象类,抽象类继承AbstractCollection抽象类实现了Queue接口,优先队列不允许null元素,且非线程安全的。其容器是一个object的数组。默认情况下采用的是自然排序,取出的是队列最小的元素。

    Collection c = Arrays.asList("a","b","c");
    PriorityQueue<String> pq = new PriorityQueue<String>(c);
    pq.offer("0"); // 指定的元素插入到此优先级队列
    //pq.offer(null); // 不允许插入null
    // pq.add(null); // 调用 offer方法插入元素
    pq.offer("a"); // 允许重复的值
    System.out.println(pq.remove("v"));// false 从该队列中删除指定元素的单个实例(如果存在)
    System.out.println(pq.peek()); // 检索但不删除此队列的头,不存在则返回null
    System.out.println(pq.poll()); // 检索并删除此队列的头,不存在则返回null
    System.out.println(pq.size());
    System.out.println(pq); // [a, a, c, b]
    for(Object o : pq){
        System.out.println(o); // 遍历队列中的元素
    }
    

    2--ArrayDeque 继承了AbsrtactCollection抽象类,实现了Deque接口。所以ArrayDeque拥有两者的特性。由于是两端队列,所以其顺序是按照元素插入数组中对应位置产生的。

    Collection c = Arrays.asList("a","b","c");
     ArrayDeque<String> aq = new ArrayDeque<String>(c);
     aq.addFirst("start"); // 头部插入指定元素 等同于offerFirst
     aq.addLast("end"); // 尾部插入指定元素 等同于offerLast
     //aq.add(null); // 不允许插入null
     aq.add("0"); // 末尾插入指定的元素, 调用addLast
     System.out.println(aq);
     System.out.println(aq.getFirst()); // start 检索但不删除,这个deque的第一个元素
     System.out.println(aq.getLast()); // 0 检索但不删除,这个deque的最后一个元素
     aq.offer("in"); // 调用 offerLast 再调用 addLast.实质与add一样。
     System.out.println(aq.pop()); // 删除第一个元素 调用 removeFirst 再调用 pollFirst
     System.out.println(aq.poll()); // 删除第一个元素 调用 pollFirst
     aq.push("me"); // 将元素推到第一个位置 调用 addFirst
     System.out.println(aq);
    

    六、Collections 和 Arrays 工具类

    Collections该工具类提供了大量方法对集合进行排序、查询和修改等操作,还提供了将集合对象置为不可变、对集合对象实现同步控制等方法。
    Arrays 工具类提供了将数组转换为集合的方法 Arrays.asList().

    List<String> l = Arrays.asList("a","b","c","d","e","f");
    // 对列表中的元素进行翻转
    Collections.reverse(l);
    System.out.println(l); // [f, e, d, c, b, a]
    //l.add("1"); 会抛出异常java.lang.UnsupportedOperationException,Arrays.asList()返回的是其内部类的 new ArrayList()对象
    // 而其内部类没有重写 AbstractList中的add方法,所以调用的是父类的add,而父类的add方法直接抛出异常
    List<String> nl = new ArrayList<>(l);
    nl.add("0");
    // 对列表默认顺序(自然顺序)进行排序
    Collections.sort(nl);
    System.out.println(nl); // [0, a, b, c, d, e, f]
    nl.add("aa");
    // 根据其元素的 自然顺序返回给定集合的最大小元素
    System.out.println( Collections.max(l)); // f
    System.out.println( Collections.min(l)); // a
    System.out.println(nl); // [0, a, b, c, d, e, f, aa]
    // 使用指定的随机源随机排列指定的列表
    Collections.shuffle(nl, new Random()); // 不带种子的随机数,每次都不一样。反之,每次都一样
    System.out.println(nl); // [b, aa, f, d, 0, c, a, e]
    // 如果两个指定的集合没有共同的元素,则返回 true
    System.out.println(Collections.disjoint(l, nl)); 
    

    注:
    http://www.trinea.cn/category/java/
    http://www.cnblogs.com/midiyu/p/8145503.html
    http://www.benchresources.net/java/collection-framework/
    https://blog.csdn.net/u011240877/article/category/6447444
    https://docs.oracle.com/javase/tutorial/collections/interfaces/collection.html

  • 相关阅读:
    使用PIE.htc 进行IE兼容CSS3
    好用的px转rem插件cssrem
    BOM基础知识
    css经典布局—stick footer布局
    input file 上传图片问题
    除自身以外数组的乘积
    2的幂
    反转字符串中的单词
    环形链表
    买卖股票的最佳时机2
  • 原文地址:https://www.cnblogs.com/zeo-to-one/p/9479123.html
Copyright © 2020-2023  润新知