Java集合框架概述

Java集合框架概述

对多个对象的存储

数组弊端(故需要集合)

数组在内存存储方面的的特点

  • 1、一旦初始化以后,其长度就确定了
  • 2、数组一旦定义好,其元素的类型也就确定了。我们也只能操作指定类型的数据了,比如String[] arr; int[] arr1;

数组在存储数据方面的弊端

  • 1、一旦初始化以后,其长度就不可修改
  • 2、数组中提供的方法有限,对于添加、删除、插入数据等操作、非常不便,效率不高。
  • 3、元素个数,没有现成属性或者方法使用
  • 4、数组存储数据的特点:有序、可重复。对于无序、不可重复的需求,不能满足

Collection

单列数据
List:有序,可重复
Set:无序,不可重复

Collection接口的方法

  • add

  • contains

    • 对比的时候是使用equals(),可根据需求重写
  • iterator

    • 遍历元素

      • 每次生成都是一个新的迭代器,类似“时钟”重新计时

List

1、有序可重复

  • ArrayList

    • 作为List接口的主要实现类;
      线程不安全,效率高;
      底层使用Object[] elementData存储。

    • 源码分析

      • 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);
      • jdk 8

        • ArrayList list = new ArrayList(); // 底层elementData[] 初始化为{},并没有创建长度为了10的数组
        • list.add(123); // 第一次调用add()时,底层才创建长度10的数组,并将数据123添加到elementData中
        • 后续添加与jdk 7 一样
      • jdk 7 的ArrayList的对象创建类似于单列的饿汉式,而jdk 8 中的ArrayLis的对象的创建类似于单列的懒汉式,延迟了数组的创建,节省了内存

  • LinkedList

    • 对于频繁的插入。删除操作,使用此类效率比AarrayList高;底层使用双向链表存储

    • 源码分析

      • ListeedList list = new ListeedList(); // 内部声明了Node类型的first和last属性,默认值为null
      • list.add(123); // 将123封装到Node中,创建了Node对象。
  • Vector

    • 作为List接口的古老实现类;
      线程安全,效率低;
      底层使用Object[] elementData存储。

    • 源码分析

      • jdk 7 、 8 中通过Vector()构造器创建对象时,底层都创建了长度为10的数组。在扩容方面,默认扩容为原来的数组长度的2倍。
  • List接口方法

    • 增、删、改、查、长度、遍历
    • 遍历:Iterator、foreach、for

Set

  • 概述

    • Set接口是Collection的子接口,Set接口没有提供额外的方法,都是Collection的方法
    • Set集合不允许包含相同的元素
    • Set判断两个对象是否相同不是使用==运算符,而是根据equals()方法
  • 属性

    • 无序性

      • 不等于随机性
      • 无序性:存储的数据在底层的数组中并非按照数组索引的顺序添加,而是根据数据的哈希值确定
    • 不可重复性

      • 保证添加的元素按照equals()判断时,不能返回true,即,相同的元素只能添加一个

      • Set.add()

        • 元素a先算hashCode(),通过某种算法,得到元素a应该添加到数组的位置,判断该位置上是否有元素

          • 如果此位置上没有其他元素,则元素a添加成功。

          • 如果此位置上有其他元素b(或以链表形式存在的多个元素),则比较元素a与元素b的hash值

            关于此处的链表
            jdk 7 和 jdk 8
            七上八下

            • 如果hash值不相同,则元素a添加成功,添加到链表后。
            • 如果hash值相同,进而需要调用元素a所在类的equals()方法:返回true,元素a添加失败;返回false,元素a添加成功,添加到链表后。
    • 要求

      • 1、向Set中添加的数据,其所在的类一定要重写hashCode()和equals()

      • 2、重写的hashCode()和equals()尽可能保存一致性:相同的对象必须具有相等的散列码

        • 2.1、在程序运行时,同一对象多次调用hashCode()方法应该返回相同的值
        • 2.2、当两个对象的equals()方法比较返回true时,两个对象的hashCode()方法的返回值也应相等
        • 2.3、对象中用作equals()方法比较的filed,都应该用来计算hashCode的值
  • HashSet

    • Set的主要实现类;
      线程安全;
      可以存储null值。
  • LinkedHashSet

    • HashSet的子类;
      遍历其内部数据时,可以按照添加的顺序遍历

    • 添加

      • 添加数据的时候,每个数据还维护了两个引用,记录此数据前一个数据和后一个数据
  • TreeSet

    • 可以按照添加对象的指定属性进行排序

    • 两点

      • 1、向TreeSet中添加的数据,要求是相同类的对象

      • 2、add的两种排序方式

        • 自然排序(实现Comparabel接口)

          • 比较两个对象是否相同的标准为compareTo()返回0,不再是equals()
        • 定制排序(Comparator接口)

          • 比较两个对象是否相同的标准为compare(obj1,obj2)返回0,不再是equals()
          • TreeSet treeSet = new TreeSet(comparator);

问题

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

    • 重写equals()

    • List: equals()

    • Set: (HashSet、LinkedHashSet为例):equals()、hashCode()

      • TreeSet

        • 自然排序:Comparable: CompareTo(obj)
        • 定制排序:Comparator: compare(obj1,obj2)
  • 2、ArrayList、LinkedList、Vector三者的相同点与不同点

    • 相同点

      • List的实现
    • 不同点

  • 3、List接口方法

    • 增、删、改、查、长度、遍历
  • 4、使用Iterator和foreach遍历List

  • 5、 Set存储数据的特点?常见的实现类?彼此特点

    • 从无序性和不可重复性出发去理解

Collections

是一个操作Set、List和Map等集合的工具类
其操作数组的工具类:Arrays

reverse(List)返转list

shuffle(list) 随机排序

Collections.sort(list)自然排序

Collections.sort(list,Comparator)定制排序

Collections.swap(list, int, int);交换元素位置

Collections.frequency(list, 元素) 某元素出现多少次

copy(List dest, List src)

  • 正确写法(主要size的需求)

    • List arrayList2 = Arrays.asList(new Object[arrayList1.size()]);
    • Collections.copy(arrayList2, arrayList1);

Map

双列集合
Key-Value

Map结构

  • 1、Map中的key:无序的,不可重复的,使用Set存储所有的key

    • 这就要求key所在的类,重新equals()和hashCode()
  • 2、Map中的value:无序的,可重复的,使用Collection 存储所有的value

    • 这就要求value所在类,重写equals()
  • 3、一个键值对:key-value构成了一个Entry对象,是Entry对象的两个属性

  • 4、Map中的entry:无序的,不可重复的,使用Set存储所有的entry

Map 常用方法

  • 添加、删除、修改

    • put(key,vlaue)

      • 将指定key-value添加(或修改)到当前map对象中
    • putAll(map)

      • 将m中的所有key-value对存放到当前map中
    • remove(key)

      • 移除指定key的key-value对,并返回value
    • clear()

      • 清空当前map中的所有数据
  • 元素查询操作

    • Object get(key)

      • 获取指定key对应的value
    • boolean containsKey(Object key)

      • 是否包含指定的key
    • boolean containsValue(Object value)

      • 是否包含指定的value
    • int size()

      • 返回键值对的个数
    • boolean isEmpty()

      • 判断当前map是否为空
    • boolean equals(obj)

      • 判断当前map和参数对象obj是否相等
  • 元视图操作

    • Set keySet()

      • 返回所有key构成的Set
    • Collection values()

      • 返回所有value构成的Collection集合
    • Set entrySet()

      • 返回所有key-value对构成的Set集合

HashMap

  • 主要实现类;
    线程不安全,效率高;
    存储null作为key和value

  • 子类

    • LinkedHashMap

      • 保证在遍历map元素时,可以按照添加的顺序实现遍历。

        • 原因:在原有的HashMap底层结构基础上,添加了一对指针,指向前一个和后一个元素。对于频繁的遍历操作,此类执行效率高于HashMap
      • 底层实现(了解)

        • 输出顺序按照put的顺序
        • 重写了一些代码,使得可以记录前后元素
  • 底层

    • jdk 7

      • 数组+链表
    • jdk 8

      • 数组+链表+红黑树

TreeMap

  • 保证按照添加的key-value对进行排序,实现排序遍历。此时考虑key的自然排序或者定制排序

    • 按照key进行排序,这就要求key为同一个类创建的对象
  • 底层:红黑树

Hashtable

  • 古老实现类;
    线程安全,效率低;
    不能存储null作为key和value

  • 子类

    • Properties

      • 常用来处理配置文件

        • key 和 value都是String类型
        • 存取数据时,建议使用setProperty(key,value)和getProperty(key,value)方法

面试题

  • 1、HashMap 的底层实现原理

    • jdk 7

      • HashMap map = new HashMap():

      • 1、在实例化以后,底层创建了长度是16的一维数组Entry[] table。

      • 2、~非第一次执行put~

      • 3、map.put(key1,value1):

        • 3.1、首先,调用key1所在类的hashCode()计算key1哈希值,此哈希值经过某种算法计算以后,得到在Entry数组中的存放位置。

        • 3.2、如果此位置上的数据为空,此时的key1-value1添加成功

        • 3.2、如果此位置上的数据不为空,(意味着此位置上存在一个或多个数据(以链表形式存在)),比较key1和已经存在的一个或者多个数据的哈希值:

          • 3.2.1、如果key1的哈希值与已经存在的数据的哈希值都不相同,此时key1-value1添加成功(七上八下)

          • 3.2.2、如果key1的哈希值与已经存在的某一个数据(key2-value2)的哈希值相同,继续比较:调用key1所在类的equals(key2)

            • 3.2.2.1、如果equals()返回false:key1-value1添加成功
            • 3.2.2.2、如果equals()返回true:使用value1替换value2
    • jdk 8

      • 与 jdk7 的不同点

        • 1、new HashMap():底层没有创建一个长度为16的数组

        • 2、jdk 8底层的数组是:Node[],而非Entry[]

          • 单个Node组成结构

            • Hash

              • Key
              • Value
        • 3、首次调用put()方法时,底层创建长度为16的数组

        • 4、jdk 7 底层结构只有:数组+链表。jdk 8 中底层结构:数组+链表+红黑树

          • 当数组的某一个索引位置上的元素以链表形式存在的数据个数 > 8且当前数组的长度 > 64 时,此时索引位置上的所有数据改为使用红黑树存储。

            • 原因:为了快速索引,查找对比
    • jdk 8 源码分析

      • 重要常量

        • DEFAULT_INITIAL_CAPACITY

          • HashMap的默认容量:16
        • MAXIMUM_CAPACITY

          • HashMap的最大支持容量:2^30
        • DEFAULT_LOAD_FACTOR

          • HashMap的默认加载因子:0.75
        • TREEIFY_THRESHOLD

          • Bucket中链表长度大于该默认值,转化为红黑树:8
        • UNTREEIFY_THRESHOLD

          • Bucket中的红黑树存储的Node小于该默认值,转化为链表
        • MIN_TREEIFY_CAPACITY

          • 桶中的Node被树化时最小的hash表容量。
          • 当桶中Node的数量大到需要变红黑树时,若hash表容量小于MIN_TREEIFY_CAPACITY时,此时应该执行resize扩容操作这个MIN_TREEIFY_CAPACITY的值至少是TREEIFY_THRESHOLD的四倍 : 64
        • table

          • 存储元素的数组,总是2^n
        • entrySet

          • 存储具体元素的集
        • size

          • HashMap中存储的键值对的数量
        • modeCount

          • HashMap扩容和结构改变的次数
        • threshold

          • 扩容的临界值 = 容量 * 填充因子

            • 16 * 0.75 = 12

              • 这数值,太小的话,很快就执行扩容操作,数组就有点浪费资源
              • 这数值,太大的话,就是比较迟才扩容,但是很多时候链表很长了,数组还是没填充满,有位置剩。链表太长对索引查找不友好。
        • loadFactor

          • 填充因子

            • 其大小决定了HashMap的数据密度
    • 扩容

      • 扩容为原来容量的2倍,并将原有的数据复制过来
  • 2、HashMap 和 Hashtable的异同

  • 3、CurrentHashMap 与 Hashtable 的异同

使用:iterator.hasNext()和iterator.Next()

框架

= 注解+反射机制+设计模式

异常

throw

  • 生成一个异常对象,并抛出。使用在方法内部
  • 自动抛出异常对象

throws

  • 处理异常的方式。使用在方法声明处的末尾
  • try-catch-finally
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值