集合很简单?开什么玩笑?肝了一周,全是精华,万字讲解,面试再不怕集合问题了_集合简单吗

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新网络安全全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上网络安全知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以添加V获取:vip204888 (备注网络安全)
img

正文

目录

Q1:说⼀说 ArrayList

Q2:说⼀说 LinkedList

Q3:ArrayList和LinkList的区别

Q4:Set 有什么特点,有哪些实现?

Q5:TreeMap 有什么特点?

Q6:HashMap 有什么特点?

Q7:HashMap为什么线程不安全?

Q8:说下你对HaspMap的认识!【重点,重点】

Q9:HashMap和HashTable的区别


Q1:说⼀说 ArrayList

ArrayList 是容量可变的⾮线程安全列表,使⽤数组实现,集合扩容时会创建更⼤的数组,把原有数组复制到新数组。⽀持对元素的快速随机访问,但插⼊与删除速度很慢。ArrayList 实现了 RandomAcess 标记接⼝,如果⼀个类实现了该接⼝,那么表示使⽤索引遍历⽐迭代器更快。

elementData是 ArrayList 的数据域,被 transient 修饰,序列化时会调⽤ writeObject 写⼊流,反序列化时调⽤ readObject 重新赋值到新对象的 elementData。原因是 elementData 容量通常⼤于实际存储元素的数量,所以只需发送真正有实际值的数组元素。size 是当前实际大小,elementData ⼤⼩⼤于等于 size。

modCount 记录了 ArrayList 结构性变化的次数,继承⾃ AbstractList。所有涉及结构变化的⽅法都会增加该值。expectedModCount 是迭代器初始化时记录的 modCount 值,每次访问新元素时都会检查modCount 和 expectedModCount 是否相等,不相等就会抛出异常。这种机制叫做 fail-fast,所有集合类都有这种机制。

Q2:说⼀说 LinkedList

LinkedList 本质是双向链表,与 ArrayList 相⽐插⼊和删除速度更快,但随机访问元素很慢。除继承AbstractList 外还实现了 Deque 接⼝,这个接⼝具有队列和栈的性质。成员变量被 transient 修饰,原理和 ArrayList 类似。

LinkedList 包含三个重要的成员:size、first 和 last。size 是双向链表中节点的个数,first 和 last 分别指向⾸尾节点的引用。

LinkedList    的优点在于可以将零散的内存单元通过附加引⽤的方式关联起来,形成按链路顺序查找的线性结构,内存利⽤率较⾼。

Q3:ArrayList和LinkList的区别

看一段简单的ArrayList和LinkList的代码,具体的大家可以自己去看下;
ArrayList:

public ArrayList(int initialCapacity) {
    if (initialCapacity > 0) {
        this.elementData = new Object[initialCapacity];
    } else if (initialCapacity == 0) {
        this.elementData = EMPTY_ELEMENTDATA;
    } else {
        throw new IllegalArgumentException("Illegal Capacity: "+
                                           initialCapacity);
    }
}

/**
 * Constructs an empty list with an initial capacity of ten.
 */
public ArrayList() {
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

/**
 * Constructs a list containing the elements of the specified
 * collection, in the order they are returned by the collection's
 * iterator.
 *
 * @param c the collection whose elements are to be placed into this list
 * @throws NullPointerException if the specified collection is null
 */
public ArrayList(Collection<? extends E> c) {
    elementData = c.toArray();
    if ((size = elementData.length) != 0) {
        // c.toArray might (incorrectly) not return Object[] (see 6260652)
        if (elementData.getClass() != Object[].class)
            elementData = Arrays.copyOf(elementData, size, Object[].class);
    } else {
        // replace with empty array.
        this.elementData = EMPTY_ELEMENTDATA;
    }
}

/**
 * Trims the capacity of this <tt>ArrayList</tt> instance to be the
 * list's current size.  An application can use this operation to minimize
 * the storage of an <tt>ArrayList</tt> instance.
 */
public void trimToSize() {
    modCount++;
    if (size < elementData.length) {
        elementData = (size == 0)
          ? EMPTY_ELEMENTDATA
          : Arrays.copyOf(elementData, size);
    }
}

类继承图关系:

LinkList:

public class LinkedList<E> extends AbstractSequentialList<E> implements

 List<E>, Deque<E>, Cloneable, java.io.Serializable {}

类继承图关系:


 
数据结构实现:ArrayList 是动态数组的数据结构实现,而 LinkedList 是双向链表的数据结构实现。

随机访问效率:ArrayList 比 LinkedList 在随机访问的时候效率要高,因为 LinkedList 是线性的数据存储方式,所以需要移动指针从前往后依次查找。

增加和删除效率:在非首尾的增加和删除操作,LinkedList 要比 ArrayList 效率要高,因为 ArrayList 增删操作要影响数组内的其他数据的下标。

综合来说,在需要频繁读取集合中的元素时,更推荐使用 ArrayList,而在插入和删除操作较多时,更推荐使用 LinkedList。

  1. 是否保证线程安全: ArrayList 和 LinkedList 都是不同步的,也就是不保证线程安全;

  2. 底层数据结构: Arraylist 底层使用的是 Object 数组;LinkedList 底层使用的是 双向链表 数据结构(JDK1.6之前为循环链表,JDK1.7取消了循环。注意双向链表和双向循环链表的区别,下面有介绍到!)

  3. 插入和删除是否受元素位置的影响: ① ArrayList 采用数组存储,所以插入和删除元素的时间复杂度受元素位置的影响。 比如:执行add(E e) 方法的时候, ArrayList 会默认在将指定的元素追加到此列表的末尾,这种情况时间复杂度就是O(1)。但是如果要在指定位置 i 插入和删除元素的话(add(int index, E element) )时间复杂度就为 O(n-i)。因为在进行上述操作的时候集合中第 i 和第 i 个元素之后的(n-i)个元素都要执行向后位/向前移一位的操作。 ② LinkedList 采用链表存储,所以对于add( E e)方法的插入,删除元素时间复杂度不受元素位置的影响,近似 O(1),如果是要在指定位置i插入和删除元素的话((add(int index, E element)) 时间复杂度应为o(n))因为需要新创立一个新的链表,复制前i-1个元素并在第i位加入新的元素,最后附上n-i个元素。

  4. 是否支持快速随机访问: LinkedList 不支持高效的随机元素访问,而 ArrayList 支持。快速随机访问就是通过元素的序号快速获取元素对象(对应于get(int index) 方法)。

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

Q4:Set 有什么特点,有哪些实现?

Set 不允许元素重复且⽆序,常⽤实现有 HashSet、LinkedHashSet 和 TreeSet。
 
HashSet 通过 HashMap 实现,HashMap 的 Key 即 HashSet 存储的元素,所有 Key 都使⽤相同的Value ,⼀个名为 PRESENT 的 Object 类型常量。使⽤ Key 保证元素唯⼀性,但不保证有序性。由于HashSet 是 HashMap 实现的,因此线程不安全。

HashSet 判断元素是否相同时,对于包装类型直接按值⽐较。对于引⽤类型先⽐较 hashCode 是否相同,不同则代表不是同⼀个对象,相同则继续⽐较 equals,都相同才是同⼀个对象。
LinkedHashSet 继承⾃ HashSet,通过 LinkedHashMap 实现,使⽤双向链表维护元素插⼊顺序。
TreeSet 通过 TreeMap 实现的,添加元素到集合时按照⽐较规则将其插⼊合适的位置,保证插⼊后的集合仍然有序。

Q5:TreeMap 有什么特点?

TreeMap 基于红⿊树实现,增删改查的平均和最差时间复杂度均为 O(logn) ,最⼤特点是 Key 有序。

Key 必须实现 Comparable 接⼝或提供的 Comparator ⽐较器,所以 Key 不允许为 null。
HashMap 依靠hashCode和equals去重,⽽ TreeMap 依靠 Comparable 或 Comparator。
TreeMap 排序时,如果⽐较器不为空就会优先使⽤⽐较器的compare⽅法,否则使⽤ Key 实现的。
 
Comparable 的Compareto⽅法,两者都不满⾜会抛出异常。TreeMap 通过put和deleteEntry实现增加和删除树节点。插⼊新节点的规则有三个:① 需要调整的新节点总是红⾊的。② 如果插⼊新节点的⽗节点是⿊⾊的,不需要调整。③ 如果插⼊新节点的⽗节点是红⾊的,由于红⿊树不能出现相邻红⾊,进⼊循环判断,通过重新着⾊或左右旋转来调整。TreeMap 的插⼊操作就是按照 Key 的对⽐往下遍历,⼤于节点值向右查找,⼩于向左查找,先按照⼆叉查找树的特性操作,后续会重新着⾊和旋转,保持红⿊树的特性。

Q6:HashMap 有什么特点?

JDK8 之前底层实现是数组 + 链表,JDK8 改为数组 + 链表/红⿊树,节点类型从Entry 变更为 Node。主要成员变量包括存储数据的 table 数组、元素数量 size、加载因⼦ loadFactor。

table 数组记录 HashMap 的数据,每个下标对应⼀条链表,所有哈希冲突的数据都会被存放到同⼀条链表,Node/Entry 节点包含四个成员变量:key、value、next 指针和 hash 值。

HashMap 中数据以键值对的形式存在,键对应的 hash 值⽤来计算数组下标,如果两个元素 key 的hash 值⼀样,就会发⽣哈希冲突,被放到同⼀个链表上,为使查询效率尽可能⾼,键的 hash 值要尽可能分散。

HashMap 默认初始化容量为 16,扩容容量必须是 2 的幂次⽅、最⼤容量为 1<< 30 、默认加载因⼦为
0.75。

Q7:HashMap为什么线程不安全?

大家都应该知道HashMap不是线程安全的。具体存在问题的场景有:

1.    数据丢失
2.    数据重复
3.    死循环

关于死循环的问题,在Java8中个人认为是不存在了,在Java8之前的版本中之所以出现死循环是因为在resize的过程中对链表进行了倒序处理;在Java8中不再倒序处理,自然也不会出现死循环。

曾经有大神这样解释的:

通过上面Java7中的源码分析一下为什么会出现数据丢失,如果有两条线程同时执行到这条语句 table[i]=null,时两个线程都会区创建Entry,这样存入会出现数据丢失。 如果有两个线程同时发现自己都key不存在,而这两个线程的key实际是相同的,在向链表中写入的时候第一线程将e设置为了自己的Entry,而第二个线程执行到了e.next,此时拿到的是最后一个节点,依然会将自己持有是数据插入到链表中,这样就出现了数据 重复。 通过商品put源码可以发现,是先将数据写入到map中,再根据元素到个数再决定是否做resize.在resize过程中还会出现一个更为诡异都问题死循环。 这个原因主要是因为hashMap在resize过程中对链表进行了一次倒序处理。假设两个线程同时进行resize, A->B 第一线程在处理过程中比较慢,第二个线程已经完成了倒序编程了B-A 那么就出现了循环,B->A->B.这样就出现了就会出现CPU使用率飙升。 在下午突然收到其中一台机器CPU利用率不足告警,将jstack内容分析发现,可能出现了死循环和数据丢失情况,当然对于链表的操作同样存在问题。 PS:在这个过程中可以发现,之所以出现死循环,主要还是在于对于链表对倒序处理,在Java 8中,已经不在使用倒序列表,死循环问题得到了极大改善。

HashMap的线程不安全主要体现在下面两个方面:

1.在JDK1.7中,当并发执行扩容操作时会造成环形链和数据丢失的情况。
2.在JDK1.8中,在并发执行put操作时会发生数据覆盖的情况。

Q8:说下你对HaspMap的认识!【重点,重点】

首先大家都知道HashMap是一个集合,是<key、value>的集合,每个节点都有一个key和value,具体的参考代码:

static class Node<K,V> implements Map.Entry<K,V> {
   final int hash;
   final K key;
   V value;
   Node<K,V> next;

Hashmap的数组结构为数组+(链表或者红黑树)

为什么要采用这种结构来存储元素呢?首先得分析下数组和链表的特点:

数组:查询效率高,插入,删除效率低。

链表:查询效率低,插入删除效率高。

在HashMap底层使用数组加(链表或红黑树)的结构完美的解决了数组和链表的问题,使得查询和插入,删除的效率都很高。

HashMap的继承图:

还有兄弟不知道网络安全面试可以提前刷题吗?费时一周整理的160+网络安全面试题,金九银十,做网络安全面试里的显眼包!

王岚嵚工程师面试题(附答案),只能帮兄弟们到这儿了!如果你能答对70%,找一个安全工作,问题不大。

对于有1-3年工作经验,想要跳槽的朋友来说,也是很好的温习资料!

【完整版领取方式在文末!!】

93道网络安全面试题

内容实在太多,不一一截图了

黑客学习资源推荐

最后给大家分享一份全套的网络安全学习资料,给那些想学习 网络安全的小伙伴们一点帮助!

对于从来没有接触过网络安全的同学,我们帮你准备了详细的学习成长路线图。可以说是最科学最系统的学习路线,大家跟着这个大的方向学习准没问题。

1️⃣零基础入门
① 学习路线

对于从来没有接触过网络安全的同学,我们帮你准备了详细的学习成长路线图。可以说是最科学最系统的学习路线,大家跟着这个大的方向学习准没问题。

image

② 路线对应学习视频

同时每个成长路线对应的板块都有配套的视频提供:

image-20231025112050764

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注网络安全)
img

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

nter)

② 路线对应学习视频

同时每个成长路线对应的板块都有配套的视频提供:

image-20231025112050764

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注网络安全)
[外链图片转存中…(img-WZks56l6-1713664038987)]

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 30
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值