Java基础常见面试题总结-集合(一)

常见的集合有哪些?

Java集合类主要由两个接口CollectionMap派生出来的,Collection有三个子接口:List、Set、Queue。

Java集合框架图如下:

img

img

List代表了有序可重复集合,可直接根据元素的索引来访问;Set代表无序不可重复集合,只能根据元素本身来访问;Queue是队列集合。Map代表的是存储key-value对的集合,可根据元素的key来访问value。

集合体系中常用的实现类有ArrayList、LinkedList、HashSet、TreeSet、HashMap、TreeMap等实现类。

List 、Set和Map 的区别

  • List 以索引来存取元素,有序的,元素是允许重复的,可以插入多个null;
  • Set 不能存放重复元素,无序的,只允许一个null;
  • Map 保存键值对映射;
  • List 底层实现有数组、链表两种方式;Set、Map 容器有基于哈希存储和红黑树两种方式实现;
  • Set 基于 Map 实现,Set 里的元素值就是 Map的键值。

ArrayList 了解吗?

ArrayList 的底层是动态数组,它的容量能动态增长。在添加大量元素前,应用可以使用ensureCapacity操作增加 ArrayList 实例的容量。ArrayList 继承了 AbstractList ,并实现了 List 接口。

ArrayList 的扩容机制?

ArrayList扩容的本质就是计算出新的扩容数组的size后实例化,并将原有数组内容复制到新数组中去。默认情况下,新的容量会是原容量的1.5倍。以JDK1.8为例说明:

public boolean add(E e) {
    //判断是否可以容纳e,若能,则直接添加在末尾;若不能,则进行扩容,然后再把e添加在末尾
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    //将e添加到数组末尾
    elementData[size++] = e;
    return true;
    }

// 每次在add()一个元素时,arraylist都需要对这个list的容量进行一个判断。通过ensureCapacityInternal()方法确保当前ArrayList维护的数组具有存储新元素的能力,经过处理之后将元素存储在数组elementData的尾部

private void ensureCapacityInternal(int minCapacity) {
      ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}

private static int calculateCapacity(Object[] elementData, int minCapacity) {
        //如果传入的是个空数组则最小容量取默认容量与minCapacity之间的最大值
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        return minCapacity;
    }
    
  private void ensureExplicitCapacity(int minCapacity) {
        modCount++;
        // 若ArrayList已有的存储能力满足最低存储要求,则返回add直接添加元素;如果最低要求的存储能力>ArrayList已有的存储能力,这就表示ArrayList的存储能力不足,因此需要调用 grow();方法进行扩容
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }


private void grow(int minCapacity) {
        // 获取elementData数组的内存空间长度
        int oldCapacity = elementData.length;
        // 扩容至原来的1.5倍
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        //校验容量是否够
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        //若预设值大于默认的最大值,检查是否溢出
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // 调用Arrays.copyOf方法将elementData数组指向新的内存空间
         //并将elementData的数据复制到新的内存空间
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

怎么在遍历 ArrayList 时移除一个元素?

foreach删除会导致快速失败问题,可以使用迭代器的 remove() 方法。

Iterator itr = list.iterator();
while(itr.hasNext()) {
      if(itr.next().equals("jay") {
        itr.remove();
      }
}

Arraylist 和 Vector 的区别

  1. ArrayList在内存不够时扩容为原来的1.5倍,Vector是扩容为原来的2倍。
  2. Vector属于线程安全级别的,但是大多数情况下不使用Vector,因为操作Vector效率比较低。

Arraylist 与 LinkedList的区别

  1. ArrayList基于动态数组实现;LinkedList基于链表实现。
  2. 对于随机index访问的get和set方法,ArrayList的速度要优于LinkedList。因为ArrayList直接通过数组下标直接找到元素;LinkedList要移动指针遍历每个元素直到找到为止。
  3. 新增和删除元素,LinkedList的速度要优于ArrayList。因为ArrayList在新增和删除元素时,可能扩容和复制数组;LinkedList实例化对象需要时间外,只需要修改指针即可。

HashMap

HashMap 使用数组+链表+红黑树(JDK1.8增加了红黑树部分)实现的, 链表长度大于8(TREEIFY_THRESHOLD)时,会把链表转换为红黑树,红黑树节点个数小于6(UNTREEIFY_THRESHOLD)时才转化为链表,防止频繁的转化。

解决hash冲突的办法有哪些?HashMap用的哪种?

解决Hash冲突方法有:开放定址法、再哈希法、链地址法。HashMap中采用的是 链地址法 。

  • 开放定址法基本思想就是,如果p=H(key)出现冲突时,则以p为基础,再次hash,p1=H(p),如果p1再次出现冲突,则以p1为基础,以此类推,直到找到一个不冲突的哈希地址pi。 因此开放定址法所需要的hash表的长度要大于等于所需要存放的元素,而且因为存在再次hash,所以只能在删除的节点上做标记,而不能真正删除节点。
  • 再哈希法提供多个不同的hash函数,当R1=H1(key1)发生冲突时,再计算R2=H2(key1),直到没有冲突为止。 这样做虽然不易产生堆集,但增加了计算的时间。
  • 链地址法将哈希值相同的元素构成一个同义词的单链表,并将单链表的头指针存放在哈希表的第i个单元中,查找、插入和删除主要在同义词链表中进行。链表法适用于经常进行插入和删除的情况。

使用的hash算法?

Hash算法:取key的hashCode值、高位运算、取模运算。

h=key.hashCode() //第一步 取hashCode值
h^(h>>>16)  //第二步 高位参与运算,减少冲突
return h&(length-1);  //第三步 取模运算

在JDK1.8的实现中,优化了高位运算的算法,通过hashCode()的高16位异或低16位实现的:这么做可以在数组比较小的时候,也能保证考虑到高低位都参与到Hash的计算中,可以减少冲突,同时不会有太大的开销。

为什么建议设置HashMap的容量?

HashMap有扩容机制,就是当达到扩容条件时会进行扩容。扩容条件就是当HashMap中的元素个数超过临界值时就会自动扩容(threshold = loadFactor * capacity)。

如果我们没有设置初始容量大小,随着元素的不断增加,HashMap会发生多次扩容。而HashMap每次扩容都需要重建hash表,非常影响性能。所以建议开发者在创建HashMap的时候指定初始化容量。

扩容过程?

1.8扩容机制:当元素个数大于threshold时,会进行扩容,使用2倍容量的数组代替原有数组。采用尾插入的方式将原数组元素拷贝到新数组。1.8扩容之后链表元素相对位置没有变化,而1.7扩容之后链表元素会倒置。

1.7链表新节点采用的是头插法,这样在线程一扩容迁移元素时,会将元素顺序改变,导致两个线程中出现元素的相互指向而形成循环链表,1.8采用了尾插法,避免了这种情况的发生。

原数组的元素在重新计算hash之后,因为数组容量n变为2倍,那么n-1的mask范围在高位多1bit。在元素拷贝过程不需要重新计算元素在数组中的位置,只需要看看原来的hash值新增的那个bit是1还是0,是0的话索引没变,是1的话索引变成“原索引+oldCap”(根据e.hash & oldCap == 0判断) 。这样可以省去重新计算hash值的时间,而且由于新增的1bit是0还是1可以认为是随机的,因此resize的过程会均匀的把之前的冲突的节点分散到新的bucket。

put方法流程?

  1. 如果table没有初始化就先进行初始化过程
  2. 使用hash算法计算key的索引
  3. 判断索引处有没有存在元素,没有就直接插入
  4. 如果索引处存在元素,则遍历插入,有两种情况,一种是链表形式就直接遍历到尾端插入,一种是红黑树就按照红黑树结构插入
  5. 链表的数量大于阈值8,就要转换成红黑树的结构
  6. 添加成功后会检查是否需要扩容

img

红黑树的特点?

  • 每个节点或者是黑色,或者是红色。
  • 根节点和叶子节点(NIL)是黑色的。
  • 如果一个节点是红色的,则它的子节点必须是黑色的。
  • 从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点。

在解决 hash 冲突的时候,为什么选择先用链表,再转红黑树?

因为红黑树需要进行左旋,右旋,变色这些操作来保持平衡,而单链表不需要。所以,当元素个数小于8个的时候,采用链表结构可以保证查询性能。而当元素个数大于8个的时候并且数组容量大于等于64,会采用红黑树结构。因为红黑树搜索时间复杂度是 O(logn),而链表是 O(n),在n比较大的时候,使用红黑树可以加快查询速度。

HashMap 的长度为什么是 2 的幂次方?

Hash 值的范围值比较大,使用之前需要先对数组的长度取模运算,得到的余数才是元素存放的位置也就是对应的数组下标。这个数组下标的计算方法是(n - 1) & hash。将HashMap的长度定为2 的幂次方,这样就可以使用(n - 1)&hash位运算代替%取余的操作,提高性能。

HashMap默认加载因子是多少?为什么是 0.75?

先看下HashMap的默认构造函数:

int threshold;             // 容纳键值对的最大值
final float loadFactor;    // 负载因子
int modCount;  
int size;  

Node[] table的初始化长度length为16,默认的loadFactor是0.75,0.75是对空间和时间效率的一个平衡选择,根据泊松分布,loadFactor 取0.75碰撞最小。一般不会修改,除非在时间和空间比较特殊的情况下 :

  • 如果内存空间很多而又对时间效率要求很高,可以降低负载因子Load factor的值 。
  • 如果内存空间紧张而对时间效率要求不高,可以增加负载因子loadFactor的值,这个值可以大于1。

一般用什么作为HashMap的key?

一般用IntegerString这种不可变类当 HashMap 当 key。String类比较常用。

  • 因为 String 是不可变的,所以在它创建的时候`hashcode``就被缓存了,不需要重新计算。这就是 HashMap 中的key经常使用字符串的原因。
  • 获取对象的时候要用到 equals()hashCode() 方法,而Integer、String这些类都已经重写了 hashCode() 以及 equals() 方法,不需要自己去重写这两个方法。

HashMap为什么线程不安全?

  • 多线程下扩容死循环。JDK1.7中的 HashMap 使用头插法插入元素,在多线程的环境下,扩容的时候有可能导致环形链表的出现,形成死循环。
  • 在JDK1.8中,在多线程环境下,会发生数据覆盖的情况。

HashMap和HashTable的区别?

HashMap和Hashtable都实现了Map接口。

  1. HashMap可以接受为null的key和value,key为null的键值对放在下标为0的头结点的链表中,而Hashtable则不行。
  2. HashMap是非线程安全的,HashTable是线程安全的。Jdk1.5提供了ConcurrentHashMap,它是HashTable的替代。
  3. Hashtable很多方法是同步方法,在单线程环境下它比HashMap要慢。
  4. 哈希值的使用不同,HashTable直接使用对象的hashCode。而HashMap重新计算hash值。

LinkedHashMap底层原理?

HashMap是无序的,迭代HashMap所得到元素的顺序并不是它们最初放到HashMap的顺序,即不能保持它们的插入顺序。

LinkedHashMap继承于HashMap,是HashMap和LinkedList的融合体,具备两者的特性。每次put操作都会将entry插入到双向链表的尾部。

讲一下TreeMap?

TreeMap是一个能比较元素大小的Map集合,会对传入的key进行了大小排序。可以使用元素的自然顺序,也可以使用集合中自定义的比较器来进行排序。

public class TreeMap<K,V>
    extends AbstractMap<K,V>
    implements NavigableMap<K,V>, Cloneable, java.io.Serializable {
}

TreeMap 的继承结构:

img

TreeMap的特点:

  1. TreeMap是有序的key-value集合,通过红黑树实现。根据键的自然顺序进行排序或根据提供的Comparator进行排序。
  2. TreeMap继承了AbstractMap,实现了NavigableMap接口,支持一系列的导航方法,给定具体搜索目标,可以返回最接近的匹配项。如floorEntry()、ceilingEntry()分别返回小于等于、大于等于给定键关联的Map.Entry()对象,不存在则返回null。lowerKey()、floorKey、ceilingKey、higherKey()只返回关联的key。

HashSet底层原理?

HashSet 基于 HashMap 实现。放入HashSet中的元素实际上由HashMap的key来保存,而HashMap的value则存储了一个静态的Object对象。

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; //基于HashMap实现
    //...
}

HashSet、LinkedHashSet 和 TreeSet 的区别?

HashSetSet 接口的主要实现类 ,HashSet 的底层是 HashMap,线程不安全的,可以存储 null 值;

LinkedHashSetHashSet 的子类,能够按照添加的顺序遍历;

TreeSet 底层使用红黑树,能够按照添加元素的顺序进行遍历,排序的方式可以自定义。

什么是fail fast?

fast-fail是Java集合的一种错误机制。当多个线程对同一个集合进行操作时,就有可能会产生fast-fail事件。例如:当线程a正通过iterator遍历集合时,另一个线程b修改了集合的内容,此时modCount(记录集合操作过程的修改次数)会加1,不等于expectedModCount,那么线程a访问集合的时候,就会抛出ConcurrentModificationException,产生fast-fail事件。边遍历边修改集合也会产生fast-fail事件。

解决方法:

  • 使用Colletions.synchronizedList方法或在修改集合内容的地方加上synchronized。这样的话,增删集合内容的同步锁会阻塞遍历操作,影响性能。
  • 使用CopyOnWriteArrayList来替换ArrayList。在对CopyOnWriteArrayList进行修改操作的时候,会拷贝一个新的数组,对新的数组进行操作,操作完成后再把引用移到新的数组。

什么是fail safe?

采用安全失败机制的集合容器,在遍历时不是直接在集合内容上访问的,而是先复制原有集合内容,在拷贝的集合上进行遍历。java.util.concurrent包下的容器都是安全失败,可以在多线程下并发使用,并发修改。

原理:由于迭代时是对原集合的拷贝进行遍历,所以在遍历过程中对原集合所作的修改并不能被迭代器检测到,所以不会触发Concurrent Modification Exception。

缺点:基于拷贝内容的优点是避免了Concurrent Modification Exception,但同样地,迭代器并不能访问到修改后的内容,即:迭代器遍历的是开始遍历那一刻拿到的集合拷贝,在遍历期间原集合发生的修改迭代器是不知道的。

讲一下ArrayDeque?

ArrayDeque实现了双端队列,内部使用循环数组实现,默认大小为16。它的特点有:

  1. 在两端添加、删除元素的效率较高
  2. 根据元素内容查找和删除的效率比较低。
  3. 没有索引位置的概念,不能根据索引位置进行操作。

ArrayDeque和LinkedList都实现了Deque接口,如果只需要从两端进行操作,ArrayDeque效率更高一些。如果同时需要根据索引位置进行操作,或者经常需要在中间进行插入和删除(LinkedList有相应的 api,如add(int index, E e)),则应该选LinkedList。

ArrayDeque和LinkedList都是线程不安全的,可以使用Collections工具类中synchronizedXxx()转换成线程同步。

哪些集合类是线程安全的?哪些不安全?

线性安全的集合类:

  • Vector:比ArrayList多了同步机制。
  • Hashtable。
  • ConcurrentHashMap:是一种高效并且线程安全的集合。
  • Stack:栈,也是线程安全的,继承于Vector。

线性不安全的集合类:

  • Hashmap
  • Arraylist
  • LinkedList
  • HashSet
  • TreeSet
  • TreeMap

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

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

相关文章

寒假作业-day7

1>现有文件test.c\test1.c\main.c , 请编写Makefile. 代码&#xff1a; CCgcc EXEstr OBJS$(patsubst %.c,%.o,$(wildcard *.c)) CFLAGS-c -oall:$(EXE)$(EXE):$(OBJS)$(CC) $^ -o $%.o:%.c$(CC) $(CFLAGS) $ $^head.o:head.hclean:rm $(OBJS) $(EXE) 2>C编程实现&…

Uniapp(uni-app)学习与快速上手教程

Uniapp&#xff08;uni-app&#xff09;学习与快速上手教程 1. 简介 Uniapp是一个跨平台的前端框架&#xff0c;允许您使用Vue.js语法开发小程序、H5、安卓和iOS应用。下面是快速上手的步骤。 2. 创建项目 2.1 可视化界面创建 1、打开 HBuilderX&#xff0c;这是一款专为uni…

docker 基于容器创建本地web容器化镜像

一、docker 基于容器创建本地web容器化镜像 1、启动指定buysbox 镜像 docker run --name b1 -it busybox:latest 2、创建目录&#xff0c;并创建html mkdir -p /data/html vi index.html 内容自定义例如&#xff1a;<h1>welcome to busybox<h1> 3、新增窗口&am…

基于麻雀优化算法优化XGBoost参数的优化控制策略

目录 一、背景 二、算法流程图 三、附录 一、背景 为提高极端梯度提升&#xff08;Extreme Gradient Boosting, XGBoost&#xff09;集成算法在时间预测、信贷风险预测、工件参数预测、故障诊断预测等方面中的准确性&#xff0c;研究者提出了一种改进的麻雀算法&#xff08;…

leetcode:62.不同路径

动态规划 注意&#xff1a;用深搜或者广搜会超时 dp含义dp[i,j]&#xff1a;从&#xff08;0&#xff0c;0&#xff09;到&#xff08;i&#xff0c;j&#xff09;的路径个数 递推公式&#xff1a;dp[i][j] dp[i-1][j] dp[i][j-1] 初始化&#xff1a;for(i 0,i<m,i) …

python_蓝桥杯刷题记录_笔记_全AC代码_入门4

题单目录 1.P1914 小书童——凯撒密码 2.P1028 [NOIP2001 普及组] 数的计算 3.P1036 [NOIP2002 普及组] 选数 4.P1149 [NOIP2008 提高组] 火柴棒等式 5.P1217 [USACO1.5] 回文质数 Prime Palindromes 6.P1478 陶陶摘苹果&#xff08;升级版&#xff09; 7.P1618 三连击&…

移动端设置position: fixed;固定定位,底部出现一条缝隙,不知原因,欢迎探讨!!!

1、问题 在父盒子中有一个子盒子&#xff0c;父盒子加了固定定位&#xff0c;需要子盒子上下都有要边距&#xff0c;用margin或者padding挤开时&#xff0c;会出现缝隙是子盒子背景颜色的。 测试过了&#xff0c;有些手机型号有&#xff0c;有些没有&#xff0c;微信小程序同移…

数字图像处理实验记录六(图像的傅里叶变换和频域处理)

前言&#xff1a; 一、基础知识 1&#xff0c;傅里叶变换是什么 傅里叶变换是一种线性积分变换&#xff0c;通俗来说&#xff0c;通过傅里叶变换就是把一段信号分解成若干个简谐波。 二、实验要求 1&#xff0e;产生一幅如图所示亮块图像f(x,y)&#xff08;256256 大小、…

[UI5 常用控件] 08.Wizard,NavContainer

文章目录 前言1. Wizard1.1 基本结构1.2 属性1.2.1 Wizard&#xff1a;complete1.2.2 Wizard&#xff1a;finishButtonText1.2.3 Wizard&#xff1a;currentStep1.2.4 Wizard&#xff1a;backgroundDesign1.2.5 Wizard&#xff1a;enableBranching1.2.6 WizardStep&#xff1a;…

[红日靶机渗透] ATKCK红队评估实战靶场三

&#x1f36c; 博主介绍&#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 hacker-routing &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【应急响应】 【ATK&CK红队评估实战靶场】 【VulnHub靶场复现】【面试分析】 &#x1f…

Ubuntu22.04 gnome-builder gnome C 应用程序习练笔记(一)

一、序言 gnome-builder构建器是gnome程序开发的集成环境&#xff0c;支持主力语言C, C, Vala, jscript, python等&#xff0c;界面以最新的 gtk 4.12 为主力&#xff0c;将其下版本的gtk直接压入了depreciated&#xff0c;但gtk4.12与普遍使用的gtk3有很大区别&#xff0c;原…

【C++】引用与内联

个人主页 &#xff1a; zxctsclrjjjcph 文章封面来自&#xff1a;艺术家–贤海林 如有转载请先通知 文章目录 1. 前言2. 引用2.1 引用概念2.2 引用使用场景2.3 引用特性2.4 引用和指针的区别2.5 传值、传引用效率比较2.5.1 值和引用的作为返回值类型的性能比较 3. 内联函数3.1 …

Vue事件中如何使用 event 对象

在Vue中&#xff0c;事件处理函数常常需要获取事件触发时的相关信息&#xff0c;比如鼠标位置、按键信息等。而要获取这些信息&#xff0c;就需要使用event对象。那么在Vue的事件中如何正确使用event对象呢&#xff1f;接下来就来详细介绍一下。 首先&#xff0c;在Vue的事件中…

JUC-并发面试题

一、基础 1、为什么要并发编程 充分利用多核CPU的资源2、并发编程存在的问题 上下文切换:PU通过时间片分配算法来循环执行任务,当前任务执行一个时间片后会切换到下一个任务。在切换前会保存上一个任务的状态,以便下次切换回这个任务时,可以再加载这个任务的状态。任务从保…

国考试题答案?五个不限次的公众号和软件分享啦! #学习方法#学习方法

在如今的智能化时代&#xff0c;我们的生活离不开手机&#xff0c;有许多工具能让生活更加方便&#xff0c;那么今天小招就介绍几款&#xff0c;在大学生活中常用的软件&#xff0c;给即将到来的小萌新们 1.灵兔搜题 这个是公众号 题库内容丰富全面&#xff0c;细致分类整理…

PySpark(三)RDD持久化、共享变量、Spark内核制度,Spark Shuffle、Spark执行流程

目录 RDD持久化 RDD 的数据是过程数据 RDD 缓存 RDD CheckPoint 共享变量 广播变量 累加器 Spark 内核调度 DAG DAG 的宽窄依赖和阶段划分 内存迭代计算 Spark是怎么做内存计算的? DAG的作用?Stage阶段划分的作用? Spark为什么比MapReduce快&#xff1f; Spa…

Qt网络编程-TCP与UDP

网络基础 TCP与UDP基础 关于TCP与UDP的基础这里就不过多介绍了&#xff0c;具体可以查看对应百度百科介绍&#xff1a; TCP&#xff08;传输控制协议&#xff09;_百度百科 (baidu.com) UDP_百度百科 (baidu.com) 需要知道这两者的区别&#xff1a; 可靠性&#xff1a; TC…

报道|2024 INFORMS Franz Edelman奖决赛名单

编者按 近日&#xff0c;2024年INFORMS Franz Edelman奖公布了决赛名单。Franz Edelman奖旨在促进能拯救生命、节省金钱以及解决问题的研究。决赛名单包含了零售、航空、食物供应链以及可持续发展等领域的优秀研究。 NFORMS近日发文&#xff0c;公布了进入2024 INFORMS Franz E…

如何在 emacs 上开始使用 Tree-Sitter (archlinux)

文章目录 如何在emacs上开始使用Tree-Sitter&#xff08;archlinux&#xff09; 如何在emacs上开始使用Tree-Sitter&#xff08;archlinux&#xff09; 在archlinux上使用比windows上不知道要方便多少倍&#xff01; $ sudo pacman -S emacs $ sudo pacman -S tree-sitter这里…

了解物联网漏洞与家庭网络入侵之间的联系

我们的家庭正日益成为一个由互连设备组成的网络。从智能恒温器到联网冰箱&#xff0c;物联网 (IoT) 彻底改变了我们与家庭环境互动的方式。 随着技术进步带来了新的挑战&#xff1a;这些设备容易受到网络威胁以及随之而来的家庭网络入侵风险。 在这篇博文中&#xff0c;我们将…
最新文章