Java集合(八股)

这里写目录标题

  • Collection 接口
    • List 接口
        • ArrayList 简述
      • 1. ArrayList 和 LinkedList 区别?⭐️⭐️⭐️⭐️
      • 2. ArrayList 和 Array 的区别?⭐️⭐️⭐️
      • ArrayList 和 Vector 区别?⭐️⭐️
      • ArrayList 的扩容机制?⭐️⭐️⭐️
    • Queue 接口
      • 1. Queue和Deque的区别?⭐️⭐️⭐️
      • 2. ArrayDeque与LinkedList区别?⭐️⭐️⭐️
      • 3. PriorityQueue有什么特点?⭐️⭐️⭐️
    • Set 接口
  • Map 接口
    • 简述HashMap
      • (1)HashMap查询、删除的时间复杂度⭐️⭐️⭐️⭐️
      • (2)HashMap的底层实现⭐️⭐️⭐️⭐️⭐️
    • 1. HashMap和HashTable的区别
    • 2. HashMap和HashSet区别⭐️⭐️⭐️⭐️
    • 3. HashMap和TreeMap的区别?⭐️⭐️⭐️⭐️
    • 4. CocurrentHashMap线程安全的具体实现方式/底层具体实现⭐️⭐️⭐️⭐️

!!!本文是基于javaGuide的学习和自我总结!!!

集合有两大接口CollectionMap,Collection中存单一元素,Map中存放kv对
from javaGuide
(图片 from javaGuide)

Collection 接口

List 接口

在这里插入图片描述

ArrayList 简述
public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable{...}

ArrayList
继承了AbstractList类;
实现了ListRandomAccessCloneableSerializable接口

  • List:表明他是一个列表,支持增删查等操作、
  • RandomAccess:表明List集合是支持快速随机访问
注:
这只是一个标志接口,不是实现了它就能快速随机访问,
还要看类的底层逻辑
(如LinkedList就算继承了RandomAccess,也无法实现随机访问,因为它底层是链表,内存地址是不连续的 , 所以注定不可能)
  • Cloneable:表明它具有拷贝能力,可以进行深拷贝和浅拷贝
  • Serializable:表明它可以进行序列化操作,也就是可以将对象转换为字节流进行持久化存储或网络传输

1. ArrayList 和 LinkedList 区别?⭐️⭐️⭐️⭐️

首先说明 :
貌似绝大多数情况都是使用ArrayList , 就算是需要用到LinkedList的情况 ,也是可以用ArrayList替代掉的 , 且性能会更好
在这里插入图片描述

  • 是否线程安全

都不是线程安全的,因为他俩都是不同步的(源码中没有任何“同步”的想法)

  • 底层数据结构
  • ArrayList 底层使用的是Object数组
  • ListedList 底层使用的是双向链表
  • 插入和删除是否受元素位置的影响
  • ArrayList 采用数组存储,所以插入和删除的时间复杂度 受元素位置的影响。
比如:
执行 `add(E e)`方法时,ArrayList会默认在末尾追加元素,时间复杂度是O(1)
执行`add(int index, E element)`,ArrayList会让第i个及以后元素 全部移动一位,时间复杂度是O(n)
  • ListedList 采用链表存储,插入、删除头尾元素不受影响,指定索引的插入删除操作受影响
执行`add(E e)` `addFirst(E e)``addLast(E e)``removeFirst()``removeLast()` 时间复杂度为O(1)
执行`add(int index, E element)` `remove(Object o)` `remove(int index)`时间复杂度为O(n),因为需要先移动到指定位置再插入和删除 
  • 是否支持快速随机访问

ArrayList 支持 --> 实现了RandomAccess的接口
ListedList不支持

  • 内存空间占用
  • ArrayList 的空间浪费主要体现在 : list列表结尾会预留一定容量的空间
  • LinkedList 的空间花费则体现在 : 每个元素都需要消耗比ArrayList更多的空间 (因为都要存放直接后继和直接前驱以及数据)

2. ArrayList 和 Array 的区别?⭐️⭐️⭐️

  • Array

Array(数组) 就是一个可以自定义固定长度数组 , 只能按照下标访问元素 , Array里面没有定义什么便于使用的方法
最常用的可能就是Array.length() 和 Array.sort()

  • ArrayList
    ArrayList<Integer> list = new ArrayList();

ArrayList 内置了丰富的API操作方法 , 比如add() , remove()等
它会根据实际存储的元素动态扩容
允许使用泛型 来确保类型安全
只能存储对象

ArrayList 和 Vector 区别?⭐️⭐️

它们底层都是使用Object()存储

  • Vector比较老了 , 但它是线程安全的(很少使用了)
  • ArrayList , 适用于频繁的查找工作 ; 线程不安全

ArrayList 的扩容机制?⭐️⭐️⭐️

  • ArrayList的默认长度是10,当然也可以自定义
  • 当数组存储的元素 数量大于10的时候,就会触发扩容机制(也就是grow()方法)
  • grow()方法 会创建一个新的数组,这个新数组的长度大约是原来的1.5倍(grow中的移位运算 算出来的)
  • 然后通过Arrays.copyOf()方法将老数组赋值到新数组当中
  • 以此类推

ArrayList的扩容机制的核心其实是grow()方法

/**
 * 要分配的最大数组大小
 */
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

/**
 * ArrayList扩容的核心方法。
 */
private void grow(int minCapacity) {
    // oldCapacity为旧容量,newCapacity为新容量
    int oldCapacity = elementData.length;
    // 将oldCapacity 右移一位,其效果相当于oldCapacity /2,
    // 我们知道位运算的速度远远快于整除运算,整句运算式的结果就是将新容量更新为旧容量的1.5倍,
    int newCapacity = oldCapacity + (oldCapacity >> 1);

    // 然后检查新容量是否大于最小需要容量,若还是小于最小需要容量,那么就把最小需要容量当作数组的新容量,
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;

    // 如果新容量大于 MAX_ARRAY_SIZE,进入(执行) `hugeCapacity()` 方法来比较 minCapacity 和 MAX_ARRAY_SIZE,
    // 如果minCapacity大于最大容量,则新容量则为`Integer.MAX_VALUE`,否则,新容量大小则为 MAX_ARRAY_SIZE 即为 `Integer.MAX_VALUE - 8`。
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);

    // minCapacity is usually close to size, so this is a win:
    elementData = Arrays.copyOf(elementData, newCapacity);
}

Queue 接口

在这里插入图片描述

1. Queue和Deque的区别?⭐️⭐️⭐️

主要区别就是

Queue是单端队列
Deque是双端队列

本质上

  • Queue : public interface Queue<E> extends Collection<E> {...}
  • Deque : public interface Deque<E> extends Queue<E> {...}
  • Deque继承了Queue接口,并且扩展了在队头和队尾增删元素的方法
  • 事实上,Deque还提供有push()和pop()等其他方法,可用于模拟栈

2. ArrayDeque与LinkedList区别?⭐️⭐️⭐️

ArrayDeque和LinkedList都继承了Deque,两者有什么不同吗?

  • ArrayDeque
  1. ArrayDeque是基于可变数组和双指针实现的;LinkedList是基于链表实现
//ArrayDeque
transient Object[] elements;	//数组	
transient int head;	//头指针
transient int tail;	//尾指针
  1. ArrayDeque 不能添加null值,原因如下(源码);LinkedList可以
public void addFirst(E e) {
       if (e == null)
           throw new NullPointerException();
       elements[head = (head - 1) & (elements.length - 1)] >= e;
       if (head == tail)
      	   doubleCapacity();
}
  1. ArrayDeque是在jdk1.6才被引入的;LinkedList早就存在
  2. ArrayDeque 插入时存在扩容过程
  3. ArrayDeque性能更好

图片 from javaGuide
在这里插入图片描述

3. PriorityQueue有什么特点?⭐️⭐️⭐️

特点:元素出队顺序是与优先级相关的,即总是优先级最高的元素先出队

PriorityQueue会出现在手撕算法应用当中 --》堆排序、第K大的数、带权图的遍历等

Set 接口

Map 接口

在这里插入图片描述

简述HashMap

  • Map里面存放的是KV对,且Key值不可重复(这一点很重要,事关HashSet为啥不可重复,因为HashSet直接把值存到Key上了,Value则赋值为一个虚拟的Object对象)
  • 这篇文章很详细,不过比较老了:深入Java集合学习系列:HashMap的实现原理

(1)HashMap查询、删除的时间复杂度⭐️⭐️⭐️⭐️

  • 如果没有元素

处理:直接插入元素或者直接返回未找到
时间复杂度:O(1)

  • 如果有元素(链表)

处理:沿着链表遍历
时间复杂度:O(n)

  • 红黑树

时间复杂度O(longn)

(2)HashMap的底层实现⭐️⭐️⭐️⭐️⭐️

  1. 基于Map接口实现
public class HashMap<K,V> extends AbstractMap<K,V>
   implements Map<K,V>, Cloneable, Serializable {...}
  1. 非线程安全
  2. HashMap的存储方法;解决哈希冲突
- JDK1.8之前,HashMap由 数组+链表 组成的,数组是HashMap的主题,链表则主要是为了解决哈希冲突而存在的(“拉链法”);
- JDK1.8以后得HashMap在解决哈希冲突时有了较大的变化,
-- 当链表的长度大于等于阈值(默认为8)时,
-- 会判断当前数组的长度是否小于64,
-- 如果小于64,则先进行数组扩容,
-- 如果大于64,则将链表转化为红黑树,以减少搜索时间
  1. HashMap默认初始化大小为16,之后每次扩充,容量变为原来的2倍。并且,HashMap总是使用2的幂作为哈希表的大小

1. HashMap和HashTable的区别

注 : HashTable基本被淘汰了

  • 线程安全

HashMap 线程不安全
HashTable 线程安全(HashTable内的方法基本都被synchronized修饰)

  • 效率

因为线程安全问题,所以HashTable的效率会低一些

  • 对Null key和Null value的支持

HashMap可以存储null的key和value,但null作为键只能有一个,null作为值可以有多个
HashTable不允许有null键和null值

  • 其他区别可以从上面写的HashMap来说(HashTable几乎不用了)

2. HashMap和HashSet区别⭐️⭐️⭐️⭐️

HashSet<Object> objects = new HashSet();
HashMap<Object, Object> objectObjectHashMap = new HashMap();
  • 区别:

HashMap里面存的是KV对 ;HashSet里存的是对象
HashMap的Key不可重复,Value可重复;HashSet不可重复
HashSet的add方法调用了HashMap中的put方法

// HashSet部分源码

public class HashSet<E>
    extends AbstractSet<E>
    implements Set<E>, Cloneable, java.io.Serializable
{
    static final long serialVersionUID = -5024744406713321676L;

    private transient HashMap<E,Object> map;

    // Dummy value to associate with an Object in the backing Map
    private static final Object PRESENT = new Object();

    /**
     * Constructs a new, empty set; the backing <tt>HashMap</tt> instance has
     * default initial capacity (16) and load factor (0.75).
     */
    public HashSet() {
        map = new HashMap<>();
    }
    ...
    // 这里,调用了map的put方法,把e存到key上---》不能重复
    public boolean add(E e) {
        return map.put(e, PRESENT)==null;
    }
}

可以看出,HashSet底层就是基于HashMap实现的(HashSet的源码非常少,因为除了clone() , writeObject() , readObject() 是HashSet自己不得不实现之外,其他方法都是直接调用HashMap中的方法)

3. HashMap和TreeMap的区别?⭐️⭐️⭐️⭐️

相比于HashMap来说,TreeMap主要多了对集合中元素根据键排序以及对于集合内元素的搜索的能力

//HashMap

public class HashMap<K,V> extends AbstractMap<K,V>
    implements Map<K,V>, Cloneable, Serializable {

//TreeMap

public class TreeMap<K,V>
    extends AbstractMap<K,V>
    implements NavigableMap<K,V>, Cloneable, java.io.Serializable
  • TreeMap实现了NavigableMap接口

实现NavigableMap接口让TreeMap有了对集合内元素的搜索能力

  • NavigableMap接口提供了丰富的方法来探索和操作键值对
  • TreeMap实现了SortedMap接口

实现SortedMap接口让TreeMap有了对集合中的元素根据键排序的能力。

  • 默认是按照key的升序排序,不过我们也可以指定排序的比较器

4. CocurrentHashMap线程安全的具体实现方式/底层具体实现⭐️⭐️⭐️⭐️

分两个阶段——jdk1.8之前;1.8及以后

  • jdk1.8以前
    在这里插入图片描述

首先将数据分成一段一段(这个“端”就是Segment)的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据时,其他段的数据也能被其他线程访问

ConcurrentHashMap是由Segment数据结构和HashEntry数据结构组成

Segment的结构和1.8以前的HashMap类似
在这里插入图片描述

  • jdk1.8及以后
    在这里插入图片描述
    在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/878688.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

18063 圈中的游戏

### 思路 1. 创建一个循环链表表示围成一圈的 n 个人。 2. 从第一个人开始报数&#xff0c;每报到 3 的人退出圈子。 3. 重复上述过程&#xff0c;直到只剩下一个人。 4. 输出最后留下的人的编号。 ### 伪代码 1. 创建一个循环链表&#xff0c;节点表示每个人的编号。 2. 初始…

Vue3+TS项目封装一个公共的el-table组件二次封装

前言 支持动态传入列&#xff0c;列内容可以指定插槽&#xff0c;指定格式化显示 样式没太写&#xff0c;主要分享基础功能封装 效果 Table组件代码BaseTable.vue <template><el-table :data"data" border><template v-for"col in columns&q…

通过防火墙分段增强网络安全

什么是网络分段‌ 随着组织规模的扩大&#xff0c;管理一个不断扩大的网络成为一件棘手的事情&#xff0c;同时确保安全性、合规性、性能和不间断的运行可能是一项艰巨的任务。为了克服这一挑战&#xff0c;网络管理员部署了网络分段&#xff0c;这是一种将网络划分为更小且易…

react18基础教程系列-- 框架基础理论知识mvc/jsx/createRoot

react的设计模式 React 是 mvc 体系&#xff0c;vue 是 mvvm 体系 mvc: model(数据)-view(视图)-controller(控制器) 我们需要按照专业的语法去构建 app 页面&#xff0c;react 使用的是 jsx 语法构建数据层&#xff0c;需要动态处理的的数据都要数据层支持控制层: 当我们需要…

YoloV8 trick讲解

1.将 YOLOv5 的 C3结构换成了梯度流更丰富的 C2f结构: C3 C3 模块的设计灵感来自 CSPNet&#xff0c;其核心思想是将特征图的部分通道进行分割和并行处理&#xff0c;目的是减少冗余梯度信息&#xff0c;同时保持较高的网络表达能力。C3 结构与传统的残差结构类似&#xff0c;但…

PMBOK® 第六版 定义活动

目录 读后感—PMBOK第六版 目录 定义活动的过程强调专业分工&#xff0c;将工作包分解成不同的活动&#xff0c;再由专业人员将这些活动细化为具体任务&#xff0c;分配给项目成员完成。 在软件开发项目中&#xff0c;定义活动将项目流程细化为需求分析、系统设计、编码、测试…

了解MySQL 高可用架构:主从备份

为了防止数据库的突然挂机&#xff0c;我们需要对数据库进行高可用架构。主从备份是常见的场景&#xff0c;通常情况下都是“一主一从/(多从)”。正常情况下&#xff0c;都是主机进行工作&#xff0c;从机进行备份主机数据&#xff0c;如果主机某天突然意外宕机&#xff0c;从机…

CPU 和 GPU:为什么GPU更适合深度学习?

目录 什么是 CPU &#xff1f; 什么是 GPU &#xff1f; GPU vs CPU 差异性对比分析 GPU 是如何工作的 &#xff1f; GPU 与 CPU 是如何协同工作的 &#xff1f; GPU vs CPU 类型解析 GPU 应用于深度学习 什么是 CPU &#xff1f; CPU&#xff08;中央处理器&#xff09;…

学习大数据DAY57 新的接口配置

作业  完成 API 接口和文件的接入, 并部署到生产调度平台, 每个任务最后至少 要有两条 不报错 的日志, 报错就驳回作业  作业不需要复制日志 API Appliation Program Interface 应用程序接口 > JSON 的地址 客户需求: 把 https://zhiyun.pub:9099/site/c-class…

nginx安装及vue项目部署

安装及简单配置 在usr/local下建好nginx文件夹&#xff0c;下载好nginx-1.26.2.tar.gz压缩文件.安装编译工具及库文件 yum -y install make zlib zlib-devel gcc-c libtool openssl openssl-devel pcre-devel gcc、gcc-c # 主要用来进行编译相关使用 openssl、ope…

大模型笔记03--快速体验dify

大模型笔记03--快速体验dify 介绍部署&测试部署 dify测试dify对接本地ollama大模型对接阿里云千问大模型在个人网站中嵌入dify智能客服 注意事项说明 介绍 Dify 是一款开源的大语言模型(LLM) 应用开发平台。它融合了后端即服务&#xff08;Backend as Service&#xff09;…

使用mlp算法对Digits数据集进行分类

程序功能 这个程序使用多层感知机&#xff08;MLP&#xff09;对 Digits 数据集进行分类。程序将数据集分为训练集和测试集&#xff0c;创建并训练一个具有两个隐藏层的 MLP 模型。训练完成后&#xff0c;模型对测试数据进行预测&#xff0c;并通过准确率、分类报告和混淆矩阵…

鸿蒙 ArkUI组件二

ArkUI组件&#xff08;续&#xff09; 文本组件 在HarmonyOS中&#xff0c;Text/Span组件是文本控件中的一个关键部分。Text控件可以用来显示文本内容&#xff0c;而Span只能作为Text组件的子组件显示文本内容。 Text/Span组件的用法非常简单和直观。我们可以通过Text组件来显…

Spring-IOC容器-ApplicationContext

IOC:Inversion of Control 控制反转&#xff0c;是一种设计原则&#xff0c;spring 中通过DI&#xff08;dependency Injection&#xff09;来具体实现。 比如原本对象的实例化&#xff0c;是通过程序主动New出来&#xff0c;IOC中的对象实例交给Spring框架来实例化&#xff0…

TDengine 与 SCADA 强强联合:提升工业数据管理的效率与精准

随着时序数据库&#xff08;Time Series Database&#xff09;的日益普及&#xff0c;越来越多的工业自动化控制&#xff08;工控&#xff09;人员开始认识到其强大能力。然而&#xff0c;时序数据库在传统实时数据库应用领域&#xff0c;特别是在过程监控层的推广仍面临挑战&a…

使用docker配置wordpress

docker的安装 配置docker yum源 sudo yum install -y yum-utils sudo yum-config-manager \ --add-repo \ http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo下载最新版本docker sudo yum install -y docker-ce docker-ce-cli containerd.io docker-buildx-…

门磁模块详解(防盗感应开关 STM32)

目录 一、介绍 二、程序设计 main.c文件 gate_guard.h文件 gate_guard.c文件 三、实验效果 四、资料获取 项目分享 一、介绍 MC-38常闭式门磁开关是作为IO开关输入数字信号的&#xff0c;原理是合在一起信号是导通的 , 配合有线主机使用 不能单独使用。适用于非铁质&a…

Linux——应用层自定义协议与序列化

目录 一应用层 1再谈 "协议" 2序列化与反序列化 3理解read,write,recv,send 4Udp vs Tcp 二网络版本计算器 三手写序列和反序列化 四进程间关系与守护进程 1进程组 1.1什么是进程组 1.2组长进程 2会话 2.1什么是会话 2.2会话下的前后台进程 3作业控…

08_Python数据类型_字典

Python的基础数据类型 数值类型&#xff1a;整数、浮点数、复数、布尔字符串容器类型&#xff1a;列表、元祖、字典、集合 字典 字典&#xff08;Dictionary&#xff09;是一种可变容器模型&#xff0c;它可以存储任意类型对象&#xff0c;其中每个对象都存储为一个键值对。…

C++ | Leetcode C++题解之第407题接雨水II

题目&#xff1a; 题解&#xff1a; class Solution { public:int trapRainWater(vector<vector<int>>& heightMap) {int m heightMap.size(), n heightMap[0].size();int maxHeight 0;int dirs[] {-1, 0, 1, 0, -1};for (int i 0; i < m; i) {maxHei…