美文网首页
集合的操作

集合的操作

作者: marjorie叶子 | 来源:发表于2019-02-25 10:10 被阅读0次

    集合框架的一些概念

    一些概念

    1. 集合Collection有两种:
      List:元素是有序的,元素可以重复,因为该集合体有索引
        ArrayList:
          底层数据结构是数组,查询快,增删慢。
          线程不安全,效率高。
          当元素放满了后,以原长度的50%+1的长度加长集合容器的长度。
        Vector:
          底层数据结构是数组,查询快,增删慢。
          线程安全,效率低。
          当元素放满了后,以原长度100%的长度加长集合容器的长度。
        LinkedList:
          底层数据结构是链表,查询慢,增删快。
          线程不安全,效率高。
          Vector(线程安全的)相对ArrayList查询慢,Vector相对LinkedList增删慢(数组结构)

    Set:元素是无序的,元素不可以重复。
        a)、HashSet:不能保证元素的排列顺序,线程不同步。
        b)、TreeSet:可以set集合中的元素进行排序,线程不同步。

    集合Map:
    Map:存储键值对
        a)、HashMap:底层是哈希表数据结构,可以存入null作为键或值,线程不同步
        b)、HashTable:底层是哈希表数据结构,不可以存入null作为键或值,线程同步
        c)、TreeMap:底层是二叉树结构,线程不同步。

    2. fail-fast与fail-safe有什么区别?
      Iterator的fail-fast属性与当前的集合共同起作用,因此它不会受到集合中任何改动的影响。Java.util包中的所有集合类都被设计为fail-fast的,而java.util.concurrent中的集合类都为fail-safe的。Fail-fast迭代器抛出ConcurrentModificationException,而fail-safe迭代器从不抛出ConcurrentModificationException。

    3. 遍历一个List<String> strList = new ArrayList<>();有哪些不同的方式?哪种方式更安全?

    //使用for-each循环
    
    for(String obj : strList){
    
      System.out.println(obj);
    
    }
    
    //using iterator
    
    Iterator<String> it = strList.iterator();
    
    while(it.hasNext()){
    
      String obj = it.next();
    
      System.out.println(obj);
    
    }
    

    说明:使用迭代器更加线程安全,因为Iterator的fail-fast属性与当前的集合共同起作用,因此它不会受到集合中任何改动的影响。它可以确保,在当前遍历的集合元素被更改的时候,它会抛出ConcurrentModificationException。在遍历一个集合的时候,我们可以使用并发集合类来避免ConcurrentModificationException,比如使用CopyOnWriteArrayList,而不是ArrayList。

    4.下面的这段代码有错吗?说说看?

    List<String> list = new ArrayList<String>(2);
    
    list.add("guan");
    
    list.add("bao");
    
    String[] array = new String[list.size()];
    
    array = list.toArray();
    

    直接使用 toArray 无参方法存在问题,此方法返回值只能是 Object[]类,若强转其它类型数组将出现 ClassCastException 错误。使用集合转数组的方法,必须使用集合的 toArray(T[] array),传入的是类型完全一样的数组,大小就是 list.size()。

    说明:使用 toArray 带参方法,入参分配的数组空间不够大时,toArray 方法内部将重新分配内存空间,并返回新数组地址;如果数组元素大于实际所需,下标为[ list.size() ]的数组元素将被置为 null,其它数组元素保持原值,因此最好将方法入参数组大小定义与集合元素个数一致。

    5.看下面这段代码:

    String[] str = new String[] { "you", "wo" };
    
    List list = Arrays.asList(str);
    

    1)如果在上述代码后添加如下代码会如何?
      list.add("yangguanbao");
    2)如果添加如下代码:输出结果是?
      str[0] = "mmzs";
      System.out.println(list.get(0));
    说明:
    使用工具类 Arrays.asList()把数组转换成集合时,不能使用其修改集合相关的方法,它的add/remove/clear 方法会抛出 UnsupportedOperationException 异常。
    asList 的返回对象是一个 Arrays 内部类,并没有实现集合的修改方法。Arrays.asList体现的是适配器模式,只是转换接口,后台的数据仍是数组。
    str[0] 改变,list.get(0)会随之修改。

    6.Iterator是什么?Iterater和ListIterator之间有什么区别?
    概念:
      Iterator接口提供遍历任何Collection的接口。我们可以从一个Collection中使用迭代器方法来获取迭代器实例。迭代器取代了Java集合框架中的Enumeration。迭代器允许调用者在迭代过程中移除元素。

    区别:
    (1)我们可以使用Iterator来遍历Set和List集合,而ListIterator只能遍历List。
    (2)Iterator只可以向前遍历,而LIstIterator可以双向遍历。
    (3)ListIterator从Iterator接口继承,然后添加了一些额外的功能,比如添加一个元素、替换一个元素、获取前面或后面元素的索引位置。

    Map相关的知识总结

    • Map主要用于存储健值对,根据键得到值,因此不允许键重复(重复了覆盖了),但允许值重复。

    Hashmap 是一个最常用的Map,它根据键的HashCode 值存储数据,根据键可以直接获取它的值,具有很快的访问速度,遍历时,取得数据的顺序是完全随机的。HashMap最多只允许一条记录的键为Null;允许多条记录的值为 Null;HashMap不支持线程的同步,即任一时刻可以有多个线程同时写HashMap;可能会导致数据的不一致。如果需要同步,可以用 Collections的synchronizedMap方法使HashMap具有同步的能力,或者使用ConcurrentHashMap。

    Hashtable与 HashMap类似,它继承自Dictionary类,不同的是:它不允许记录的键或者值为空;它支持线程的同步,即任一时刻只有一个线程能写Hashtable,因此也导致了 Hashtable在写入时会比较慢;本身是线程安全的,一般考虑登陆的候用Hashtable。

    LinkedHashMap保存了记录的插入顺序,在用Iterator遍历LinkedHashMap时,先得到的记录肯定是先插入的.也可以在构造时用带参数,按照应用次数排序。在遍历的时候会比HashMap慢,不过有种情况例外,当HashMap容量很大,实际数据较少时,遍历起来可能会比LinkedHashMap慢,因为LinkedHashMap的遍历速度只和实际数据有关,和容量无关,而HashMap的遍历速度和他的容量有关。

    TreeMap实现SortMap接口,能够把它保存的记录根据键排序,默认是按键值的升序排序,也可以指定排序的比较器,当用Iterator 遍历TreeMap时,得到的记录是排过序的。

    一般情况下,我们用的最多的是HashMap,HashMap里面存入的键值对在取出的时候是随机的,它根据键的HashCode值存储数据,根据键可以直接获取它的值,具有很快的访问速度。在Map 中插入、删除和定位元素,HashMap 是最好的选择。
    TreeMap取出来的是排序后的键值对。但如果您要按自然顺序或自定义顺序遍历键,那么TreeMap会更好。
    LinkedHashMap 是HashMap的一个子类,如果需要输出的顺序和输入的相同,那么用LinkedHashMap可以实现,它还可以按读取顺序来排列,像连接池中可以应用。

    1. HashSet是通过HashMap实现的,TreeSet是通过TreeMap实现的,只不过Set用的只是Map的key
    2. Map的key和Set都有一个共同的特性就是集合的唯一性.TreeMap更是多了一个排序的功能.
    3. hashCode和equal()是HashMap用的, 因为无需排序所以只需要关注定位和唯一性即可.
        a. hashCode是用来计算hash值的,hash值是用来确定hash表索引的.
        b. hash表中的一个索引处存放的是一张链表, 所以还要通过equal方法循环比较链上的每一个对象才可以真正定位到键值对应的Entry.
        c. put时,如果hash表中没定位到,就在链表前加一个Entry,如果定位到了,则更换Entry中的value,并返回旧value
    4. 由于TreeMap需要排序,所以需要一个Comparator为键值进行大小比较.当然也是用Comparator定位的.
        a. Comparator可以在创建TreeMap时指定
        b. 如果创建时没有确定,那么就会使用key.compareTo()方法,这就要求key必须实现Comparable接口.
        c. TreeMap是使用Tree数据结构实现的,所以使用compare接口就可以完成定位了.

    注意:
    1、Collection没有get()方法来取得某个元素。只能通过iterator()遍历元素。
    2、Set和Collection拥有一模一样的接口。
    3、List,可以通过get()方法来一次取出一个元素。使用数字来选择一堆对象中的一个,get(0)...(add/get)
    4、一般使用ArrayList。用LinkedList构造堆栈stack、队列queue。
    5、Map用 put(k,v) / get(k),还可以使用containsKey()/containsValue()来检查其中是否含有某个key/value。
      HashMap会利用对象的hashCode来快速找到key。
      【hashing 哈希码就是将对象的信息经过一些转变形成一个独一无二的int值,这个
      值存储在一个array中。 我们都知道所有存储结构中,array查找速度是最快的。
      所以,可以加速查找。
      发生碰撞时,让array指向多个values。即,数组每个位置上又生成一个梿表。】
    6、Map中元素,可以将key序列、value序列单独抽取出来。
    使用keySet()抽取key序列,将map中的所有keys生成一个Set。
    使用values()抽取value序列,将map中的所有values生成一个Collection。
    为什么一个生成Set,一个生成Collection?那是因为,key总是独一无二的,value允许重复。

    Map

    • 遍历
    /**
         * 遍历map
         */
        @Test
        public void testMap() {
            Map<String, Integer> map = new HashMap<>();
            
            map.put("zhangsan", 1000);
            map.put("lisi", 2000);
            map.put("wangwu", 3000);
            
            //第一种
            Set<Entry<String, Integer>> entrySet = map.entrySet();
            for (Entry<String, Integer> entry : entrySet) {
                System.out.println(entry.getKey() + ": " + entry.getValue());
            }
            System.out.println("---");
            //或者
            Iterator<Entry<String, Integer>> iterator1 = entrySet.iterator();
            while (iterator1.hasNext()) {
                Entry<String, Integer> next = iterator1.next();
                System.out.println(next.getKey() + ": " + next.getValue());
            }
            
            System.out.println("-----------------------------");
            
            //第二种
            Set<String> keySet = map.keySet();
            for (String key : keySet) {
                System.out.println(key + ": " + map.get(key));
            }
            System.out.println("---");
            //或者
            Iterator<String> iterator2 = map.keySet().iterator();
            while (iterator2.hasNext()) {
                String next = iterator2.next();
                System.out.println(next + ": " + map.get(next));
            }
            
            
            System.out.println("---------------------------");
            //第三种 java8新增
            map.forEach((k,v) -> System.out.println(k + ": " + v));
        }
    

    相关文章

      网友评论

          本文标题:集合的操作

          本文链接:https://www.haomeiwen.com/subject/huyqkqtx.html