Java集合(八股)

news2024/11/15 21:42:05

这里写目录标题

  • 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.coloradmin.cn/o/2130388.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Lesson08---string类(3)

1.find_first_of string里面的find成员函数就是找一个字符串然后返回第一个字符 find_first_of函数看个例子就很快就能明白 它返回的下标是参数的其中任意一个字符的下标通过以上操作就可以把原来的那一整个字符串替换成自己想要的字符 第二个参数其实就是一个缺省参数默认从0…

多种传感器输出的模拟量转换

目录 内部温度传感器与参照电压 传感器 光敏电阻 热敏电阻 反射式红外 对射式红外 驱动代码 Sensor.h Sensor.c AD.h AD.c main.c 内部温度传感器与参照电压 STM32有一个内部的温度传感器&#xff0c;可以用来测量CPU及周围的温度。 该温度传感器在内部和ADCx_I…

IBM中国研发中心撤出:挑战与机遇并存

IBM中国研发中心撤出&#xff1a;挑战与机遇并存 引言 近日&#xff0c;IBM宣布撤出在中国的两大研发中心的消息&#xff0c;引起了广泛关注。这一举动不仅对IBM自身的全球布局产生了影响&#xff0c;也在一定程度上反映了跨国公司在中国市场策略的调整。本文将探讨这一事件背…

5.9 使用LBA 的模式来读取磁盘

注意&#xff1a; 如果再 cmake 中想要 make clean 的话&#xff0c; 直接 删除 build 目录就可以了。 1 也是说 是 MBR还是 LBA 硬盘是可以控制的。 LBA 没有 磁盘&#xff0c; 柱面的概念。 2 对于寄存器的说明。 什么是 CHS呢&#xff1f; 就是机械磁盘。 这里只找到了 LB…

【计算机组成原理】详细解读带符号整数在计算机中的运算

有符号整数的运算 导读一、补码的优势二、补码的加法运算三、补码的减法运算四、原码、反码、补码的特性结语 导读 大家好&#xff0c;很高兴又和大家见面啦&#xff01;&#xff01;&#xff01; 经过前面的介绍&#xff0c;我们已经初步认识了有符号整数的三种表示形式&…

使用ShardingSphere实现MySql的分库分表

目录 一 什么是ShardingSphere分库分表 二 代码实现 1.导入相关依赖 2.配置相关参数 3.创建学生类以及mapper接口 4.实现 StandardShardingAlgorithm接口自定义分片算法 唐洋洋我知道你在看!!!嘿嘿 一 什么是ShardingSphere分库分表 我们平时在设计数据库的时候&#xf…

Servlet入门学习笔记-Servlet技术

为什么需要Servlet &#xff1f; 使用JSP技术如何编写服务器动态网页&#xff1f; 流程图&#xff1a;JSP使用Java生成动态内容 在JSP技术出现之前如何编写服务器动态网页&#xff1f; 流程图&#xff1a;Java代码就是Servlet程序 什么是Servlet &#xff1f; Servlet 是一个…

sqli-labs靶场自动化利用工具——第10关

文章目录 概要整体架构流程技术细节执行效果小结 概要 Sqli-Labs靶场对于网安专业的学生或正在学习网安的朋友来说并不陌生&#xff0c;或者说已经很熟悉。那有没有朋友想过自己开发一个测试脚本能实现自动化化测试sqli-labs呢&#xff1f;可能有些人会说不是有sqlmap&#…

YoloV10改进策略:Block改进|PromptIR(NIPS‘2023)|轻量高效,即插即用|(适用于分类、分割、检测等多种场景)

文章目录 摘要代码详解如何在自己的论文中描述摘要 本文使用PromptIR框架中的PGM模块来改进YoloV10。PGM(Prompt Generation Module)模块是PromptIR框架中的一个重要组成部分,主要负责生成输入条件化的提示(prompts)。这些提示是一组可学习的参数,它们与输入特征相互作用…

【Java】方法的重载

文章目录 前言一、方法重载是什么&#xff1f;二、方法重载的注意事项 1、一个类中&#xff0c;只要一些方法的名称相同&#xff0c;形参列表不同&#xff0c;那么它们就是方法重载了&#xff0c;其他的不管&#xff08;如&#xff1a;修饰符&#xff0c;返回值类型是否一样都无…

彻底学会防抖和节流

目录 防抖&#xff08;Debounce&#xff09; 节流&#xff08;Throttle&#xff09; 如何选择使用防抖和节流&#xff1f; 总结 Vue 3 中使用防抖&#xff08;Debounce&#xff09;和节流&#xff08;Throttle&#xff09; 防抖&#xff08;Debounce&#xff09;示例 节…

普发Pfeiffer TCP600TCP5000手侧

普发Pfeiffer TCP600TCP5000手侧

unity3d入门教程三

unity3d入门教程三 8.1游戏脚本8.2脚本的使用8.3认识脚本组件8.4帧率9.1游戏脚本9.2获取节点和组件9.3MonoBehaviour9.4父节点与子节点9.5组件的属性9.6脚本的单步调试 8.1游戏脚本 通过程序控制对象属性&#xff08;如运动&#xff0c;修改transform的位置属性&#xff09; …

【STM32】VOFA+上位机 PID调参

【STM32】VOFA上位机 PID调参 前言VOFA简介 VOFA配置VOFA动态调节PID参数VOFA控件STM32解析数据包 PID参数整定一般调节法临界比例法试凑法 前言 参考文章如下&#xff1a;VOFA使用说明 使用VOFA上位机进行PID调参 PID参数整定 VOFA VOFA是一款简单易上手的上位机调试软件&a…

vue之我不会

计算属性 例子&#xff1a; 注意&#xff1a;调用计算属性时&#xff0c;不可以带括号&#xff0c;那样调用的就是方法&#xff0c;如&#xff1a;以下调用fullName时不可funnName() <div id"root">姓&#xff1a;<input type"text" v-model"…

Go语言练习——语法实践

目录 一、数组 1.多维数组的声明和使用 2.数组与切片的转换 3.数组在函数中的使用 二、切片 1.切片的动态扩容机制 2.切片的复制与修改 3.切片在排序算法中的应用 三、结构体 1.结构体的嵌套与方法 2.结构体与JSON的序列化 3.结构体的工厂模式 四、映射 1.映射的并发访问 2.映射…

erlang学习: Mnesia Erlang数据库4

表的类型和位置 内存表 它们的速度非常快&#xff0c;但是里面的数据是易失的&#xff0c;所以如果机器崩溃或者你停止了DBMS&#xff0c;数据就会丢失。 磁盘表 磁盘表应该不会受到系统崩溃的影响&#xff08;前提是磁盘没有物理损坏&#xff09;。 当Mnesia事务写入一个表并…

Qt如何链接和使用第三方库详解

在开发Qt应用程序时&#xff0c;我们经常会遇到需要使用第三方库的情况。无论是为了实现特定的功能&#xff0c;还是为了提高开发效率&#xff0c;使用第三方库都是一个非常常见的做法。本文将详细介绍如何在Qt项目中链接和使用第三方库。 基本步骤 配置Qt项目 在Qt项目中使…

Java | Leetcode Java题解之第402题移掉K位数字

题目&#xff1a; 题解&#xff1a; class Solution {public String removeKdigits(String num, int k) {Deque<Character> deque new LinkedList<Character>();int length num.length();for (int i 0; i < length; i) {char digit num.charAt(i);while (!…

最新免费云服务器,有需要的自行领取

目前云服务器市场竞争很激烈&#xff0c;为了吸引用户上云&#xff0c;很多云服务器提供商都提供了相应的免费试用活动&#xff0c;这些活动旨在帮助用户体验其服务和产品。 以下是一些值得关注的最新免费云服务器资源及其特点&#xff1a; 一、雨云 活动地址&#xff1a;点此…