12.集合框架

  1. 什么是集合框架

    1. 存储任意数量对象的容器(只能存储引用数据类型)

      1. 能称为框架,说明这内容很多
      2. 实质:都是一些工具包
    2. 图解,这就是集合框架

      1. 虚线框:接口或抽象类
      2. 实现框:普通类
      3. 箭头:表示实现接口或继承抽象类或继承接口
      4. 说明:Collection并非继承了Iterator接口而是继承了Iterable接口
        1. Iterable接口中定义了获取迭代器的方法,由其实现类实现了
        2. Iterator接口是在java.util包中
        3. 图解
  2. 集合框架的作用

    1. 同数组一样,用于存储多个数据,但它更方便
      1. 数组的长度固定,集合长度可变
      2. 数组只能通过映射获取数组中的数据,而集合可以使用键来获取值
  3. 使用集合框架

    1. 了解常用各层次的关系与作用

      1. 关系说明(全部来于,java.util包)
        1)
        2)
    2. Collection接口下的List与Set

      1. 父级接口Collection定义的常用方法(都是通用的)

        add(obj);//添加一个元素,下标为0,其后依次增加,同数组添加元素的过程
        add(int index,obj);//根据传入的下标添加指定的元素,其后元素右移
        addAll(Collection c);//根据传入的集合添加元素

        remove(int index);//根据下标删除对象,是直删除,其后元素前移
        remove(Object obj);//根据传入的对象删除
        removeAll(Collection c);//根据传入的集合删除对应的元素
        clear()//清空所有元素,集合变成[],不是null

        直接输出对象即可查看集合中存储的数据
        seize();//获取元素个数
        isEmpty();是否是0个元素
        contains(object obj);//根据传入的对象判断是否存在
        toArray();转换成对象数组
        iterator();获取一个迭代器,它提供了一系列方法用来遍历集合的

      2. 子接口List:有序且可重复
        实现类ArrayList:它还实现了其它接口,不仅有父接口的方法还有如下特有方法

        set(int index,Object obj);//根据传入的下标设值(下标要合理),有下标范围检查,如果下标大于size会抛出异常:下标越界

          查
         	 get(int index)//根据传入下标获取元素(下标要合理)
         	 indexOf(Object obj);//根据传入的对象判断第一次出现的索引
         	 lastIndexOf(Object obj);//根据传入的对象判断最后一次出现的索引
        

        实现类LinkedList:它还实现了其它接口,不仅有父接口的方法还有如下特有方法

        addFirst(Object obj);//在链头添加对象
        push(Object obj);//就是调用的上面方法

         	 addLast(Object obj);//在链尾添加对象
          删
         	 removeFirst();//移出链头
         	 pop();//就是调用的上面方法
         		
         	 removeLast();//移出链尾
          查
         	 getFirst();//获取链头
         	 getLast();//获取链尾
        

        实现类Vector:用法同ArrayList
        ArrayList与LinkedList的异同

        前者
        基于动态数组的数据结构
        查找和修改性能高于后者(因为LinkedList要移动指针)
        后者
        基于链表的数据结构
        新增删除高于前者(因为ArrayList要移动数据)
        测试代码

          同
         	 集合长度可变
         	 只能存储引用数据类型
         	 都是非同步的
        

        ArrayList与Vector的异同
        同:集合长度可变,只能存储引用数据类型

        前者
        方法不是同步的
        ArrayList只增加50%的大小,这样,ArrayList就有利于节约内存空间
        后者
        方法都是同步的(Synchronized),是线程安全的(thread-safe)

         		 存储元素数量超过它的初始大小时,Vector会将它的容量翻倍
        
      3. 子接口Set:有时无序且不可重复
        HashSet实现类
        使用父接口的方法即可
        常用

        TreeSet实现类
        使用父接口的方法即可
        使用较少,创建实例时必须指定排序规则,否则无法添加元素(cannot be cast to java.lang.Comparable)

        HashSet与TreeSet接口的异同

        两者中的值都不能重复
        HashSet和TreeSet都是非同步
        基本操作方法使用父接口即可

        前者
        基于HashMap实现
        可以放入null,但只能放入一个null
        哈希表实现的,数据是无序的
        后者
        基于TreeMap实现
        不允许放入null值(null比较是没有意义的)
        二差树实现的,可自定义排序规则

    3. Map接口下的HashMap,TreeMap,Hashtable,ConcurrentHashMap

      1. 父级接口Map定义的常用方法(都是通用的)


        1. put(key,value);根据键值对的数据类型添加:键值


        2. remove(key);根据传入的键删除对象的值,返回被删除 的对象:如果key不存在,不会报错,此时返回null


        3. replace(键,键的新值);修改键对应的值


        4. 可直接输出

          get(key);//根据键获取值
          containsKey(key);//是否有该键
          containsValue(value);//是否有该值
          isEmpty();//是否是空
          size();//键值对的个数
          keySet();//获取键的集合
          values();//获取值的集合
          entrySet();//获取键值对集合,获取后可直接输出

      2. HashMap实现类:用Map接口中定义的方法即可

      3. TreepMap实现类:用Map接口中定义的方法即可

      4. Hashtable实现类:同上

      5. ConcurrentHashMap实现类:同上,JDK5以上使用此类代替Hashtable,它功能更强

      6. HashMap与TreeMap的异同


        1. 前者
          基于哈希散列表实现
          随机存储
          无性能损耗,建议使用(效率高)
          键、值可为null

          后者
          哈希散列表实现
          默认按键的升序排序
          插入、删除有性能损耗
          键、值都不能为null


        2. 非并发安全Map
          都是键值映射方式存储数据

      7. HashMap与Hashtable的异同

        1. 同:都是键值方式存储数据


        2. 前者
          非并发(非同步,非线程安全);
          键、值可为null

          后者
          并发
          键,值不可为null

    4. 工具类(并非集合框架成员),参考

      1. Collections
        它是什么
        它是用于操作集合的工具类,提供了很多操作集合的静态方法
        如何使用它来操作集合

        sort(List list),按自然排序的升序排序
        swap(List list, int i , int j),交换两个索引位置的元素
        boolean replaceAll(List list, Object oldVal, Object newVal), 用新元素替换旧元素
        Collections中几乎对每个集合都定义了同步控制方法
        SynchronizedList(), SynchronizedSet()等方法,来将集合包装成线程安全的集合
        singleXXX(),返回一个只包含指定对象,只有一个元素,只读的集合
        unmodifiablleXXX(),返回指定集合对象的只读视图

        int binarySearch(List list, Object key), 对List进行二分查找,返回索引,注意List必须是有序的
        int max(Collection coll),根据元素的自然顺序,返回最大的元素
        int frequency(Collection c, Object o),统计元素出现次数
        测试代码

      2. Arrays,参考 https://blog.csdn.net/daicooper/article/details/80951403 https://www.cnblogs.com/yj20hl/p/6083865.html
        它是什么:用于操作数组的工具类
        它的使用:都是使用静态方法

        copyOf(数组,复制长度);//从数组中复制指定长度复制数组并返回,下标下0开始
        copyOfRange(数组,开始,结束)//从数组中指定开始与结束下标复制数组并返回

        fill(数组,值);//用一个指定的值填充数组
        sort(数组);//默认升序排序
        asList(数组)//返回一个包装数组的 List
        asList.get(0)[0];//获取数组中的数据

        toString(数组)//转换成字符串数据格式
        deepToString(二维数组)//转换成字符串数据格式
        binarySearch(数组,开始,结束,搜索的值)//指定范围与数组然后搜索特定值的下标
        equals(数组)//使用的==比较
        Arrays.toString(arr1).equals(Arrays.toString(arr3))//根据内容比较两个数组是否相等,前提是用相同的排序规则
        测试代码

    5. Iterator迭代器

      1. 它是什么:用于遍历List集合的迭代器
      2. 使用它
        1. 用在while语句中遍历集合
          Iterator it = 集合.iterator();//由集合获取迭代器:变量的初始化
          while(it.hasNext(){//判断是否有下个元素:循环条件
          类型 变量 = it.next();//获取集合中的每个元素:循环操作
          }
        2. 用在for语句中遍历集合
          for(Itrator it = 集合.iterator();it.hasNext()😉{//同上,for把初始化,条件放一起了
          类型 变量 = it.next();//获取集合中的每个元素:循环操作
          }
        3. 测试代码
          1.
        4. 说明
          1. 迭代器可对List的任何实现类进行遍历(无论有序还是无序),不能直接对Map遍历
            List继承实现了Iterable接口(其中定义了获取迭代器的方法)
            Map接口没有继承Iterable接口,且它没有定义获取迭代器的方法,但它的keySet,Values,entrySet是集合类型,因此可用迭代器操作
            直接输出:System.out.println(hmap);//{key1=value1, key2=value2, key3=value3}
            使用iterator遍历set集合
            Set keySet = hmap.keySet();//获取键的集合
            Iterator iterator = keySet.iterator();
            for(;iterator.hasNext()😉{
            String next = iterator.next();
            System.out.println(next+"->"+hmap.get(next));//根据键获取值
            }
            使用iterator遍历entrySet集合
            Set<Entry<String,String>> entrySet = hmap.entrySet();//获取键值组成的集合
            Iterator<Entry<String, String>> iterator2 = entrySet.iterator();
            for(;iterator2.hasNext()😉{
            Entry<String, String> next = iterator2.next();
            System.out.println(next.getKey()+"="+next.getValue());
            }
            测试代码

          2. 在遍历集合时删除元素(倒数第二个除外),不能用集合的remove(obj或index)而要用迭代器的remove()方法
            正确用法

            为什么用集合的remove(obj或index)要报错,而迭代器的remove()不会报错
            根本原因:expectedModCount与modCount不同抛此异常

              iterator实例的remove方法与集合的remove()方法的区别
            

            扩展理解
            如果删除的元素是倒数第二个数的话,为何可用集合的remove()方法呢:简单的

  4. 说明

    1. 如何选择使用提高程序运行效率
      1. 如果元素个数是固定的推荐用数组
      2. 如果元素个数不是固定的推荐用集合
    2. 理解有序与无序
      1. 无序:没有排序规则
        1. 添加元素时的顺序与使用迭代器输出元素时的顺序不同即无序
      2. 有序:有排序规则
        1. 可与添加元素的顺序相同,或相反
    3. 遍历数组的几种方式
      1. while循环
        变量的初始化
        while(循环条件){
        循环操作
        }
      2. for循环
        for(变量的初始化;循环条件;变量的迭代){
        循环操作
        }
      3. 增强for循环
        for(类型 变量 : 数组名){
        循环操作
        }
    4. 遍历集合的几种方式
      1. while循环+迭代器
        根据集合获取它的迭代器
        while(迭代器.hasNext()){
        使用迭代器.next()的代码;//获取每个元素;
        }
      2. for循环+迭代器
        for(根据集合获取它的迭代器;迭代器.hasNext()😉{//迭代器自动移动不需要写变量的迭代
        使用迭代器.next()的代码;//获取每个元素;
        }
      3. 增强for循环
        for(类型 变量 : 集合名){
        循环操作
        }
        1. 隐藏的使用迭代器来遍历集合的
        2. 没有显示的iterator实例,遍历时不建议删除元素(只能用list.remove()-会报错的)
        3. 不要在 foreach 循环里进行元素的 remove/add 操作。remove 元素请使用 Iterator 方式
    5. 遍布map使用EntrySet集合,它效率高
      1.
    6. synchronized的使用方法:详细见后面
      1. 使用sychronized意味着在一次仅有一个线程能访问此方法,其它线程要等到同步锁被释放之后才能访问
    7. 多线程
posted @ 2018-09-05 17:15  River111  阅读(122)  评论(0编辑  收藏  举报