赤赤赤赤辰

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

Java集合

参考

数组和集合

    1. 集合与数据存储数据概述
集合、数组都是对多个数据进行存储操作的结构,简称Java容器
 * 说明:此时的存储,主要指的是内存层面的存储,不涉及到持久化的存储(.txt,.jpg,avi,数据库中)
    1. 数组存储的特点
 > 一旦初始化以后,其长度就确定了
 *      > 数组一旦定义好后,其元素的类型也就确定了,我们也就只能操作指定的类型数据了
 *      比如:String[] arr1; int[] arr1; Object[] arr2;
    1. 数组存储的弊端
 *      > 一旦初始化以后,其长度就不可修改
 *      > 数组中提供的方法而非常有限,对于添加,删除,插入数据等操作,非常不便,同时效率不高
 *      > 获取数组中实际元素的个数的需求,数组没有现成的属性或方法可用
 *      > 数组存储数据的特点:有序,可重复。对于无序,不可重复的需求,不能满足。
    1. 集合存储的优点

Collection接口

    1. Collection接口继承树
  • image-20210526170120332
  • 单列集合框架结构
 *  Collection接口:单列集合,用来存储一个个的对象
 *      List接口:存储有序的,可重复的数据   --->"动态的数组"
 *          |实现类--ArrayList,LinkedList,Vector
 *      Set接口:存储无序的、不可重复的数据  --->"集合"
 *          |实现类--HashSet、LinkedHashSet、TreeSet
    1. Collection接口常用方法(JDK提供的集合API位于java.util包内)
    • add(Object obj),addAll(Collection coll),size(),isEmpty(),clear()
    • contains(Object obj),containsAll(Collection coll),remve(Object obj),removeAll(Collection coll),retainAll(Collection coll),equals(Object obj)
    • hashCode(),toArray(),iterator()
    1. Collection集合与数组的转换
        //8.集合 --->数组
        Object[] arrs = coll.toArray();
        System.out.println(arrs);//输出数组hash值
        for(int i=0;i<arrs.length;i++){//输出数组内容:只能遍历
            System.out.println(arrs[i]);
        }
        System.out.println("********************");
        //拓展:数组--->集合:调用Arrays类的静态方法
        List<String> list = Arrays.asList(new String[]{"AA","bb","CC"});
        System.out.println(list);//输出集合内容

        System.out.println("**************************");
        List<int[]> arr1 = Arrays.asList(new int[]{123456,888});
        System.out.println(arr1);//[[I@61e717c2] [:一位数组 I:int
        //把new int[]{}当成一个元素
        System.out.println(arr1.size());//1

        System.out.println("09999999999999999999");
        List arr2 = Arrays.asList(new Integer[]{123456,888});
        System.out.println(arr2);//[123456, 888]
        System.out.println(arr2.size());//2
    1. 使用Collection集合存储对象,要求对象所属的类满足重写equals()

Iterator接口与for each循环

    1. 遍历Collection的两种方式
    • 迭代器Iterator
    • for each循环:
    1. java.utils包下定义的迭代器接口:Iterator
    • 说明:

      • Iterator对象称为迭代器(设计模式的一种),主要用于遍历 Collection 集合中的元素。 
      • GOF给迭代器模式的定义为:提供一种方法访问一个容器(container)对象中各个元 素,而又不需暴露该对象的内部细节。迭代器模式,就是为容器而生。类似于“公 交车上的售票员”、“火车上的乘务员”、“空姐”
    • 作用:遍历Collection元素,不包括map

    • 如何获取实例+遍历的代码实现

      Iterator it = coll.iterator();
      while(it.hasNext()){
          System.out.println(it.next());
      }
      
    • 图示说明

      image-20210529153617249

    • remove()使用

         @Test
          public void test2(){
              Collection coll = new ArrayList();
              coll.add(132);
              coll.add(new String("0ooo"));
              coll.add(new Person(3,"shc"));
              Iterator iterator=coll.iterator();
              while(iterator.hasNext()){
                  if("0ooo".equals(iterator.next())){
                      iterator.remove();//删除当前指向元素
      //   注意:
      // 如果还未调用next()或在上一次调用 next 方法之后已经调用了 remove 方法,再调用remove都会报IllegalStateException。
                  }
              }
      
              Iterator it = coll.iterator();
              while(it.hasNext()){
                  System.out.println(it.next());
              }
          }
      
  • for each就是迭代器

Collection子接口:List接口

    1. 存储的数据特点
/* Collection接口:单列集合,用来存储一个个对象
*      List接口:存储有序的,可重复的数据。-->"动态"数组,替换原有的数组
*          ArrayList类:作为List接口的主要实现类(线程不安全,效率高)底层:使用Object[]存储
*          LinkedList类:对于频繁的插入和删除操作,使用此类效率比ArrayList高,底层使用双向链表.底层:链表
*          Vector类:作为List接口的古老实现类(线程安全,效率低)(不怎么用了)/
    1. 常用方法:
 * void add(int index, Object ele):在index位置插入ele元素 * boolean addAll(int index, Collection else):从index位置开始将else中的所有元素添加进来 * Object get(int index):获取指定index位置的元素 * int indexOf(Object obj):返回obj在集合中首次出现的位置 * int lastIndexOf(Object obj):返回obj在当前集合中末次出现的位置 * Object remove(int index):移除指定index位置的元素,并返回此元素 * Object set(int index, Object ele):设置指定index位置的元素为ele * List subList(int fromIndex, int toIndex):返回从fromIndex到toIndex位置的子集合
 * 总结:常用方法 *      增:add(Object obj) *      删:remove(int idx,Object obj) *      改:set(int idx,Object obj) *      查:get(int idx) *      插入:add(int idx,Object obj) *      长度:size() *      遍历: *      ① Iterator *      ② for增强 *      ③ 普通循环
    1. 源码
    • ArrayList
 *   2. ArrayList源码分析: *   2.1 jdk 7情况下 *   ArrayList list = new ArrayList();//底层创建了长度是10的Object[]数组elementData *   list.add(123); //elementData[0] = new Integer(123); *   ... *   list.add(11) //如果此次的添加导致底层elementData数组容量不够,则扩容。 *   默认情况下,扩容为原来的1.5倍,同时需要将原有数组中的数据复制到新的数组中。 *   结论:建议开发中使用带参的构造器:ArrayList list = new ArrayList(int capacity) * *   2.2 *   jdk 8 Arraylist的变化 *      ArrayList list = new Arraylist();//底层Object[] elementData初始化为{},并没有创建数组对象 *      list.add(123) //第一次调用add()时,底层才创建了长度为10的数组,并将数据123天机道elementData对象中 * *      ... *      后续的添加和拓展与jdk 7无异 * * *   2.3 小结: *      jdk7:ArrayList对象的创建类似于单例的饿汉式 *      jdk8:                               懒汉式

​ LinkedList

 *   3. LinkedList源码分析 *      LinkedList list = new LinkedList(); 内部声明了Node类型的first和last属性,默认NULL *      list.add(123); 将123封装到Node中,创建了Node对象 * *      LinkedList是双向链表 *      节点Node *          private static class Node<E> {     *         E item;     *         Node<E> next;     *         Node<E> prev;     *     *         Node(Node<E> prev, E element, Node<E> next) {     *             this.item = element;     *             this.next = next;     *             this.prev = prev;     *         } *          } *

​ Vector

 *    4. Vector源码: *    jdk7和jdk8中通过vector()构造器创建对象时,底层都创建了长度为10的数组 *    在扩容方面。默认扩容为原来的数组长度的2倍
    1. 存储的元素的要求
    • 添加的对象,所在的类要重写equals()
* 面试题:ArrayList、LinkedList、Vector三者的异同?* 同:三鳄类都是实现了List接口,存储数据的特点相同:存储有序的,可重复的数据

Collection的子接口:Set接口

 * 1. Set接口的框架 * * Collection接口:单列集合,用于存储一个个对象 *      Set接口:存储无序的,不可重复的数据 *          HashSet类:作为Set接口的主要实现类:线程不安全,可以存储null值 *              LinkedHashSet类:作为HashSet的子类:遍历其内部数据时,可以按照添加的顺序遍历 *          TreeSet类:可以按照添加对象的指定属性,进行排序
  • 存储数据的特点:无序,不可重复
    • 具体的,以HashSet为例
    一、Set:存储无序,不可重复的数据	1. 无序性:就是因为Hash函数    2. 不重复性: 相同的元素只能添加一个
  • 元素添加过程(HashSet为例)
    二、添加元素过程,以HashSet为例。hash的挂链法    hashCode()计算位置    如果数组在此位置上无元素:则a添加在这里    如果数组在此位置上有元素:则比较元素a与元素b的hash值        如果hash值不同,则元素a挂在这条链(->)上. -----》不对吧,应该也还需要遍历这条链吧,发现都不同,再加入。。。        如果hash值相同,进而调用元素a所在类的equals()方法            equals返回true,元素a添加失败            equals返回false,元素a添加成功        (->)       jdk7:元素a放在数组里,原来元素b挂在链上    jdk8:元素b放在数组里,新加的元素a挂在链上
  • 常用方法:Set接口中没有新声明的方法,使用的都是Collection中声明的方法

  • 常用实现类

 * Set接口的框架 * Collection接口:单列集合,用于存储一个个对象 *      Set接口:存储无序的,不可重复的数据 *          HashSet类:作为Set接口的主要实现类:线程不安全,可以存储null值 *              LinkedHashSet类:作为HashSet的子类:遍历其内部数据时,可以按照添加的顺序遍历 *          TreeSet类:可以按照添加对象的指定属性,进行排序
  • 存储对象所在类要求
HashSet/LinkedHashSet要求:向HashSet和LinkedHashSet的实例中添加的数据,其所在的类一定要重写hashCode()和equals()重写技巧:对象中作用宇equals()方法比较的Field,都应该用来计算hashCodTreeSet 自然排序中,比较两个对象是否相同的标准为:compareTo()是否返回0;不再是equals()方法 定制排序中,比较两个对象是否相同的标准为:compare是否返回0;不再是equals()方法和元素内部的compareTo
  • TreeSet使用
package com.shc.java1;import org.junit.Test;import java.util.Comparator;import java.util.Iterator;import java.util.TreeSet;/** * 1. 向TreeSet中添加数据,要求是同类的对象 * * @author shc * @create 2021-05-29 14:15 */public class TreeSetTest {    @Test    public void test1(){        //1. 向TreeSet中添加数据,要求是同类的对象        //2. 加入的元素实现比较器,即实现Comparable接口:implements Comparable。实现方法compareTo        //3. 自然排序中,比较两个对象是否相同的标准为:compareTo()是否返回0;不再是equals()方法        //4. 定制排序中,比较两个对象是否相同的标准为:compare是否返回0;不再是equals()方法和元素内部的compareTo        TreeSet set = new TreeSet();        set.add(new Person(12,"Tom"));        set.add(new Person(11,"shc"));        set.add(new Person(88,"tes"));        set.add(new Person(12,"ppp"));        Iterator it = set.iterator();        while(it.hasNext()){            System.out.println(it.next());        }    }        @Test    public void test2(){        Comparator com = new Comparator() {            @Override            public int compare(Object o1, Object o2) {                if(o1 instanceof Person&&o2 instanceof Person){                    return Integer.compare(((Person)o1).getAge(), ((Person) o2).getAge());                }else{                    throw new RuntimeException("输入对象类型错误");                }            }        };//        TreeSet set = new TreeSet();比较时调用的是set里元素对象的compareTo        TreeSet set = new TreeSet(com);        set.add(new Person(12,"Tom"));        set.add(new Person(11,"shc"));        set.add(new Person(88,"tes"));        set.add(new Person(120,"ppp"));        Iterator it = set.iterator();        while(it.hasNext()){            System.out.println(it.next());        }    }}

Map接口

  • 双列集合框架:Map
    1. 常用实现类结构
/** * * Map接口:双列数据,粗出key-value对的数据。 --类似函数 *      |---HashMap类:作为Map的主要实现类,线程不安全,效率高,可以存储null的key和value *          |---LinkedHashMap类:保证在遍历map元素时,可以按照添加的顺序实现便利。 *              原因:在原有的HashMap底层结构基础上,添加了一对指针,指向前一个,后一个元素。对于频繁的遍历执行效率高于HashMap *      |---TreeMap类:保证按照添加的key-val进行排序,实现排序遍历,此时考虑key的自然排序或定制排序 *      |---Hashtable类:作为Map的古老实现类,线程安全,效率低,不能存储null的kay和value *          |---Properties类:常用来处理配置文件,key和value都是String类型   * 面试题 * 1. HashMap的底层实现原理? * 2、HashMao和Hashtable的底层原理 * 3. CurretnHashMap和Hashtable的异同?
    1. 存储结构的理解
 *  二、Map结构的理解: *  Map中的key:无序的,不可重复的,使用set存储所有的key -->要重写equals()和hashCode(),以HashMap为例。 *  Map中的value:无序的,可重复的。使用Collection存储所有的value。 -->value所在的类要重写equals() *  一个键值对:key-value构成了一个Entry对象。 *  Map中的entry:无序的,不可重复的,使用Set存储所有的entry
  • 图示

image-20210601215933212

    1. 常用方法
 *总结:常用方法: * 添加:put(Object key,Object value) * 删除:remove(Object key) * 修改:get(Object key) * 长度:size() * 遍历:keySet()/values()/entrySet()
    1. 内存结构的说明
    • HashMap在jdk7中实现原理
 *  三、HashMap的底层实现原理 *  以jdk7为例说明 *  HashMap map = new HashMap(); *  在实例化以后,底层创建了长度是16的一位数组Entry[] table *  map.put(key1,value1); *  首先,调用key1所在的类hashCode()计算key1的hash值,此hash值经过某种算法计算以后,得到Entry数组中的存放位置 *  如果此位置上的数据为空,此时的key1-value添加成功 ---情况1 *  如果此位置上的数据不畏空,(意味着此位置上存在一个或多个数据(以链表形式存在))比较key1和已经存在的一个或多个数据的hash值 *      如果key1的hash值和已经存在的数据的hahs值都不相同,则添加key1-value1. ---情况1 *      如果key1的hash值和已经存在的某一个数据(key2-value)的hash值相同,继续比较:调用key1所在的类的equals(key2) *          如果equals()返回false,此时key1-value添加成功。 --情况3 *          如果equals()返回true,使用value替换value2 * 在不断添加的过程中,会涉及到扩容问题,当超出临界值(且要存放的位置非空)时,扩容,默认的扩容为原来的二倍           * DEFAULT_INITIAL_CAPACITY : HashMap的默认容量,16 * MAXIMUM_CAPACITY : HashMap的最大支持容量,2^30 * DEFAULT_LOAD_FACTOR:HashMap的默认加载因子 * TREEIFY_THRESHOLD:Bucket中链表长度大于该默认值,转化为红黑树 * UNTREEIFY_THRESHOLD:Bucket中红黑树存储的Node小于该默认值,转化为链表

​ - jdk8与jdk7的不同之处

 * jdk8与jdk7的不同。 * 1. new HashMap():底层没有实现长度为16的数组 * 2. jdk 8底层的数组是:Node[],而非Entry[] * 3. 首次调用put()方法时,底层创建长度为16的数组 * 4. jdk底层结构只有数组+链表。jdk8中底层结构:数组+链表+红黑树 *  当数组的某一个索引位置上的元素以链表形式存在的数据>8,且当前数组元素>64时,此时此索引位置上的所有数据改为使用红黑树存储

​ - HashMap底层典型属性

 * DEFAULT_INITIAL_CAPACITY : HashMap的默认容量,16 * MAXIMUM_CAPACITY : HashMap的最大支持容量,2^30 * DEFAULT_LOAD_FACTOR:HashMap的默认加载因子 * TREEIFY_THRESHOLD:Bucket中链表长度大于该默认值,转化为红黑树 * UNTREEIFY_THRESHOLD:Bucket中红黑树存储的Node小于该默认值,转化为链表

​ - LinkedHashMapi底层原理(了解)

LInkedHashMap底层结构与HashMap相同,因为LinkedHashMap继承于HashMap,区别在于:LinkedHashMap内部使用了Entry。替换HashMap中的Node

image-20210601222850582

​ - TreeMap使用

    //向TreeMap中添加key-value,要求key必须是同一个类创建的对象    //因为要按照key进行排序:自然排序,定制排序    //自然排序 被比较元素implements Comparable
  • Collection工具类
    • 作用:操作Collection和Map的工具类。
    • 对比:Iterator:只操作Collection及其实现的籍人口

每日一考

  • 集合Collection中存储的如果是自定义类的对象,需要自定义重写哪个方法?why?

    • equals()方法
    • list也要重写equals()方法(在contains,remove啥的时候调用)
    • set:
      • (HashSet,LinkedHashSet):equals(),hashCode()。
      • (TreeSet为例)
        • Comparable:compareTo(Object obj)
        • Comparator:compareTo(Object o1,Object o2)
  • ArrayList,Linked,Vector三者的相同点于不同点?【面试题】

  • List接口的常用方法

    • 增:add(Object obj)
    • 删:reomve(Object obj)
    • 改:set(int idx,Object obj)
    • 查:get(int idx)
    • 插:add(int idx,Object obj)
    • 大小:size()
    • 遍历:Iterator;for each;for
  • 如何使用Iterator和增强for循环遍历List。举例说明

  • Set存储数据特点?常见实现类?特点?

    • HashSet,LinkedList,TreeSet

每日一考

    1. Map存储数据的特点是什么?并指明key,value,entry存储数据的特点
    • 双列数据,存储key-value对数据
    • key:无序的,不可重复的。-->Set存储
    • value:无序的,可重复的。-->Collection存储
    • key-value:无序的,不可重复。-->Set存储
    1. HashMap的底层实现原理(jdk8)(必须会)
    1. Map中常用实现类有哪些?各自特点?
    • HashMap
      • LinkedHashMap
    • TreeMap
    • Hashtable
      • Properties
    1. 如何遍历Map中的key-value对
    1. Collections和Collection的区别?
posted on 2021-08-21 15:10  咕噜辰  阅读(43)  评论(0)    收藏  举报