JAVA基础:集合框架学习笔记(未完待续)

文章目录

    • 什么是集合框架?
    • 为什么需要集合?
    • Collection接口
      • List接口
        • ArrayList、LinkedList、Vector区别
        • ArrayList解析
      • Set接口
        • HashSet
        • TreeSet
    • Map接口
      • HashMap(关于底层实现详见《数据结构:HashMap学习笔记》)
      • HashMap、HashTable、ConcurrentHashMap区别
      • 分析equals()、hashCode()与内存泄漏
    • Iterator接口
    • 集合输出
      • Collection集合输出
      • Map集合输出

本文是参阅了如下文章,并整理成的学习笔记
原文链接:1.https://thinkwon.blog.csdn.net/article/details/104588551
2. https://xiaoqi.blog.csdn.net/article/details/109092024
3. https://mp.weixin.qq.com/s?__biz=MzI4Njg5MDA5NA==&mid=2247484165&idx=1&sn=fe2aaa3ced88e9fbe153f339be695797&chksm=ebd74204dca0cb12f2b2c7988adf778b1d828ec15543556dd917235c3d97d343fe8827a951bd&scene=21###wechat_redirect

什么是集合框架?

集合框架

  • 概念:为了表示和操作集合而规定的一种统一的标准的体系结构

  • 内容:对外的接口、接口的实现、对集合运算的算法

    • 接口:集合的抽象数据类型(允许我们操作集合时不必关注具体实现,从而达到“多态”,在面向对象编程语言中,接口通常用来形成规范)

    • 实现:集合接口的具体实现,是重用性很高的数据结构

    • 算法:在一个实现了某个集合框架中的接口的对象身上完成某种有用的计算的方法,例如查找、排序等。这些算法通常是多态的,因为相同的方法可以在同一个接口被多个类实现时有不同的表现。事实上,算法是可复用的函数

集合

  • 概念:集合也叫作容器,是存储对象的容器

  • 数据结构:就是容器中存储数据的方式(每一个容器的自身特点不同,原理在于每个容器的内部数据结构(逻辑结构、物理结构)不同。

集合容器在不断向上抽取过程中,出现了集合框架/体系。
使用体系的原则:参阅顶层内容、建立底层对象

集合框架结构图
JAVA基础:集合框架学习笔记(未完待续)_第1张图片
JAVA基础:集合框架学习笔记(未完待续)_第2张图片

图片来源:https://mp.weixin.qq.com/s?__biz=MzI4Njg5MDA5NA==&mid=2247484122&idx=1&sn=c3bd6436b3e661ae15cb9d7154d82b89&chksm=ebd743dbdca0cacdcb272576f4be48c466bd73160a87227314e8fb21d5e4f9156c23902198ab&scene=21###wechat_redirect

为什么需要集合?

我们先思考一下,对象数组有哪些问题?

Java是一门面向对象的语言,就免不了处理对象,为了方便操作多个对象,那么我们就得把这多个对象存储起来。
普通的对象数组的最大问题在于数组中的元素个数是固定的,不能动态扩充大小,所以最早的时候可以通过链表实现一个动态对象线性表。但是这样做毕竟太复杂了,所以在 Java 中为了方便用户操作各个数据结构, 引入了类集的概念,有时候就可以把类集称为 Java 对数据结构的实现。 在整个类集中的,这个概念是从 JDK 1.2(Java 2)之后才正式引入的,最早也提供了很多的操作类,但是并没有完整的提出类集的完整概念。
类集中最大的几个操作接口:Collection、Map、Iterator,这三个接口为以后要使用的最重点的接口。
所有的类集操作的接口或类都在 java.util 包中。

集合与数组的区别

区别 集 合 数 组
长度 可变长度,有自动扩容机制 固定
内容 引用数据类型(存入基本数据类型会自动装箱) 基本数据类型/引用数据类型
规则 存储的对象可以是不同数据类型(比如将泛型设置成Object,emm…但是一般不这么做) 存储的元素必须是同一数据类型

集合的优点

  • 自动扩容机制

  • 提供了高性能的数据结构和算法,使编码更轻松

  • 允许不同 API之间可以来回传递集合

  • 可以方便地扩展或改写集合,提高代码复用性和可操作性

  • 通过使用JDK自带的集合类,可以降低代码维护和学习新API成本

常用集合类List、Set、Map区别

Java 容器分为 Collection 和 Map 两大类,Collection集合的子接口有Set、List、Queue三种子接口。我们比较常用的是Set、List,Map接口不是collection的子接口

Collection Map
存储单一元素 存储键值对
子接口:List、Map、Queue 常用实现类:HashMap、LinkedHashMap、ConcurrentHashMap、HashTableTreeMap
List Set
有序(元素存入集合的顺序和取出的顺序一致 无序(存入和取出顺序有可能不一致)
元素可重复 元素不重复唯一性
可以存入多个null元素 只允许存入一个null元素
常用实现类:ArrayList、LinkedList、Vector 常用实现类: HashSet、LinkedHashSet、TreeSet

Collection接口

功能 方法 描述
boolean add(E e) / boolean addAll(Collection c) 传入的数据类型必须是 Object,所以当写入基本数据类型的时候,会做自动装箱 auto-boxing 和自动拆箱 unboxing
boolean remove(Object o) / boolean removeAll(Collection c) 删除指定元素 / 删除集合c中所有元素
Collection中没有这个方法 可以使用增、删来完成
boolean contains(Object o) / boolean containsAll(Collection c) 查询集合中是否有指定元素 / 查询集合中是否包含另一个集合
其他 boolean isEmpty() / int size() / Object[] toArray() 判空 / 集合元素个数 / 把集合转换成数组

List接口

List特点:有序、可重复

ArrayList、LinkedList、Vector区别

区别 ArrayList LinkedList Vector
数据结构实现 动态数组 双向链表 动态数组
内存空间占用 - 更占内存,链表节点除了要存储数据,还要存储两个指向前后元素的引用 -
线程安全 不保证 不保证 使用了Synchronized实现线程同步
性能 适用于频繁读取元素,尾部增删(开发中更多使用ArrayList) 适用于作为算法题目中的队列 性能低于前两者
扩容 1.5倍 - 2倍

常用方法

功能 方法 ArrayList LinkedList
void add(E e) O(1) O(1)
boolean add(int index, E e) O(n) O(n)
E remove(int index) O(n) O(n)
boolean remove(E e) O(n) O(n)
E set(int index, E e) O(1) O(n)
E get(int index) O(1) O(n)

LinkedList 还有诸如peek()、poll()这样和队列相关的方法
JAVA基础:集合框架学习笔记(未完待续)_第3张图片

add(E e) :在尾部添加元素,虽然 ArrayList 可能会有扩容的情况出现,但是均摊复杂度(amortized time complexity)还是 O(1) 的。

add(int index, E e):在特定的位置上加元素
LinkedList 需要先找到这个位置,再加上这个元素,虽然单纯的「加」这个动作是 O(1) 的,但是要找到这个位置还是 O(n) 的。

remove(int index): 删除 index 下标上的元素,所以ArrayList 找到这个元素的过程是 O(1),但是 remove 之后,后续元素都要往前移动一位,所以均摊复杂度是 O(n);
LinkedList 也是要先找到这个 index,这个过程是 O(n) 的,所以整体也是 O(n)。

remove(E e)是 remove 见到的第一个这个元素,那么

ArrayList 要先找到这个元素,这个过程是 O(n),然后移除后还要往前移一位,这个更是 O(n),总的还是 O(n);
LinkedList 也是要先找,这个过程是 O(n),然后移走,这个过程是 O(1),总的是 O(n)

ArrayList解析

参见https://mp.weixin.qq.com/s?__biz=MzI4Njg5MDA5NA==&mid=2247484130&idx=1&sn=4052ac3c1db8f9b33ec977b9baba2308&chksm=ebd743e3dca0caf51b170fd4285345c9d992a5a56afc28f2f45076f5a820ad7ec08c260e7d39&scene=21###wechat_redirect
讲解的非常之详细了

选取了一些内容总结:

初始化

  • 如果指定容量,数组初始化成对应容量的Object对象数组
  • 如果指定容量为0,数组初始化为一个空数组EMPTY_ELEMENTDATA
  • 如果不指定容量,数组初始化为一个空数组DEFAULTCAPCITY_EMPTY_ELEMENTDATA

添加

添加到尾部 add(E e)

  1. 检查是否需要扩容

    • 首次添加元素,会扩容至10
    • 判断增加一个元素的长度是否比超出现在的长度,是则扩容grow(minCapacity)
    • grow1:扩容至原来容量的1.5倍(第一次扩容后,如果容量还是小于minCapacity,就将容量扩充为minCapacity)
    • grow2:调用Arrays类的copyOf方法,也就是把原来数组复制到一个指定容量的更大数组里,并把新数组引用赋给旧数组,elementData = Arrays.copyOf(ElementData, newCapacity)
  2. 添加元素

Set接口

Set特点:无序、不重复

Set 接口并没有对 Collection 接口进行扩充,基本上还是与 Collection 接口保持一致。因为此接口没有 List 接口中定义 的 get(int index)方法,所以无法使用循环进行输出。

那么,现在思考一下?能不能通过循环的方式将 Set 接口中的内容输出呢?

是可以实现的,因为在 Collection 接口中定义了将集合变为对象数组进行输出

<T> T[] toArray​(T[] a) 

例如

Set<String> hashSet = new HashSet<>();
String[] str = hashSet.toArray(new String[]{
     });
for (int x = 0; x < str.length; x++) {
      		
	System.out.print(str[x] + "、"); 
}

Set 的常用实现类有三个:

HashSet: 采用Hashmap的key来储存元素,主要特点是无序的,基本操作都是 O(1) 的时间复杂度,很快。

LinkedHashSet: 这个是一个 HashSet + LinkedList 的结构,特点就是既拥有了 O(1) 的时间复杂度,又能够保留插入的顺序

TreeSet: 采用红黑树结构,特点是可以有序,可以用自然排序或者自定义比较器来排序;缺点就是查询速度没有 HashSet 快。

每个 Set 的底层实现其实就是对应的 Map:
数值放在 map 中的 key 上,value 上放了个 PRESENT,是一个静态的 Object,相当于占位符,每个 key 都指向这个 object

HashSet

要点:

  • 实现Set接口

  • 不保证迭代顺序

  • 允许元素为null(且只能有一个null)

  • HashSet实际上就是封装了HashMap,操作HashSet元素实际- 上就是操作HashMap。这也是面向对象的一种体现,重用性高

  • 非同步

  • 初始容量非常影响迭代性能

TreeSet

Map接口

HashMap(关于底层实现详见《数据结构:HashMap学习笔记》)

HashMap、HashTable、ConcurrentHashMap区别

分析equals()、hashCode()与内存泄漏

Iterator接口

集合输出

Collection集合输出

Map集合输出

你可能感兴趣的:(JAVA)