java基础总结二(集合)(代码片段)

<天各一方> <天各一方>     2022-12-10     428

关键词:

文章目录

Java基础总结二(集合)

集合概述

什么是集合

  • 集合框架:集合就是存储数据的容器。集合框架是为表示和操作集合而规定的一种统一的标准的体系结构。
    任何集合框架都包含三大块内容:对外的接口、接口的实现和对集合运算的算法。
  • 接口:表示集合的抽象数据类型。接口允许我们操作集合时不必关注具体实现,从而达到“多态”。在面向对象编程语言中,接口通常用来形成规范。
  • 实现:集合接口的具体实现,是重用性很高的数据结构。
  • 算法:在一个实现了某个集合框架中的接口的对象身上完成某种有用的计算的方法,例如查找、排序等。这些算法通常是多态的,因为相同的方法可以在同一个接口被多个类实现时有不同的表现。事实上,算法是可复用的函数。

集合框架通过提供有用的数据结构和算法使你能集中注意力于你的程序的重要部分上,而不是为了让程序能正常运转而将注意力于低层设计上。
通过这些在无关API之间的简易的互用性,使你免除了为改编对象或转换代码以便联合这些API而去写大量的代码。 它提高了程序速度和质量。

集合和数组的区别

  • 数组是固定长度的,集合是可变长度的。
  • 数组可以存储基本数据类型,也可以存储引用数据类型。
  • 数组存储的元素必须是同一个数据类型;集合存储的对象可以是不同数据类型。

使用集合框架的好处

  1. 容量自增长。
  2. 提供了高性能的数据结构和算法,使编码更轻松,提高程序速度和质量。
  3. 可以方便的扩展或改写集合,提高代码的复用性和操作性。

常见的集合类有哪些

Map接口和Collection接口是所有集合框架的父接口:

  1. Collection接口的子接口包括:Set接口和List接口。
  2. Map接口的主要实现类有:HashMap、TreeMap、HashTable、ConcurrentHashMap、Properties等。
  3. Set接口的主要实现类有:HashSet、TreeSet、LinkedHashSet等。
  4. List接口的主要实现类有:ArrayList、LinkedList、Stack、Vector等。

简述List、Set、Map三者区别

  • Map不是Collection的子接口,List和Set是Collection的子接口。
  • List:一个有序的容器(元素的存入集合的顺序和取出的顺序一致),元素可以重复,可以插入多个null元素,常用实现类有ArrayList、LinkedList、Vector。
  • Set:一个无序的容器,不可以存储重复的元素,只允许存入一个null元素,必须保证元素的唯一性。Set 接口常用实现类是 HashSet、LinkedHashSet 以及 TreeSet。
  • Map:一个存储键值对的容器。key无序且唯一,value允许重复。Map 的常用实现类:HashMap、TreeMap、HashTable、LinkedHashMap、ConcurrentHashMap。

集合框架底层数据结构

  • List

    • ArrayList:数组。
    • Vector:数组。
    • LinkedList:双向循环链表。
  • Set

    • HashSet(无序、唯一):基于HashMap实现,底层采用HashMap来保存元素。
    • LinkedHashSet :LinkedHashSet继承与HashSet,并且内部是通过LinkedHashMap来实现的。
    • TreeSet(有序、唯一):红黑树(自平衡排序二叉树)。
  • Map

    • HashMap:JDK1.8之前是数组+链表组成的,数组是HashMap的主体,链表这是为了解决哈希冲突而存在。JDK1.8之后再解决哈希冲突时有了较大的变化,当链表大于阈值(默认为8),并且数组长度大于64,会将链表转化为红黑树,来减少搜索时间。如果数组小于64,则会先扩容。
    • LinkedHashMap :LinkedHashMap 继承自 HashMap,所以它的底层仍然是基于拉链式散列结构即由数组和链表或红黑树组成。另外,LinkedHashMap 在上面结构的基础上,增加了一条双向链表,使得上面的结构可以保持键值对的插入顺序。同时通过对链表进行相应的操作,实现了访问顺序相关逻辑。
    • TreeMap: 红黑树(自平衡的排序二叉树)。

哪些集合类是线程安全的

  • Vector:就比ArrayList多了同步化机制,因为效率低,现在已经不太建议使用。
  • Stack:堆栈类,先进后出。
  • HashTable:比HashMap多了线程安全。

集合的快速失败机制 “fail-fast”

是java集合的一种错误检测机制,当多个线程对集合进行结构上的改变的操作时,有可能会产生 fail-fast 机制。

例如:假设存在两个线程(线程1、线程2),线程1通过Iterator在遍历集合A中的元素,在某个时候线程2修改了集合A的结构(是结构上面的修改,而不是简单的修改集合元素的内容),那么这个时候程序就会抛出 ConcurrentModificationException 异常,从而产生fail-fast机制。

原因:迭代器在遍历时直接访问集合中的内容,并且在遍历过程中使用一个 modCount 变量。集合在被遍历期间如果内容发生变化,就会改变modCount的值。每当迭代器使用hashNext()/next()遍历下一个元素之前,都会检测modCount变量是否为expectedmodCount值,是的话就返回遍历;否则抛出异常,终止遍历。

解决办法:

  1. 使用并发包中的容器,如CopyOnWriteArrayList来替换ArrayList。
  2. 使用迭代器中的方法。

Collection接口

List接口

迭代器Iterator是什么?

Iterator 接口提供遍历任何 Collection 的接口。我们可以从一个 Collection 中使用迭代器方法来获取迭代器实例。迭代器取代了 Java 集合框架中的 Enumeration,迭代器允许调用者在迭代过程中移除元素。

Iterator怎么使用?有什么特点?

Iterator 使用代码如下:

List<String> list = new ArrayList<>();
Iterator<String> it = list. iterator();
while(it. hasNext())
  String obj = it. next();
  System. out. println(obj);

Iterator 的特点是只能单向遍历,但是更加安全,因为它可以确保,在当前遍历的集合元素被更改的时候,就会抛出 ConcurrentModificationException 异常。

如何边遍历边移除 Collection 中的元素?

Iterator<Integer> it = list.iterator();
while(it.hasNext())
   *// do something*
   it.remove();

一种最常见的错误代码如下:

for(Integer i : list)
   list.remove(i)

ArrayList的优缺点

  • 优点:ArrayList底层以数组实现,是一种随机访问模式,查找的时候非常快。ArrayList在顺序添加一个元素时候非常方便。
  • 缺点:插入和删除元素时需要做复制操作,如果元素很多,那么就比较耗费性能。

ArrayList和LinkedList的区别

  • 数据结构实现:ArrayList是动态数组数据结构实现,而LinkedList是双向链表的数据结构实现。
  • 访问效率:ArrayList通过索引访问效率要高,LinkedList是线性的数据存储方式,所以需要移动指针从前往后依次查找。
  • 增加和删除效率:在非尾部的增加和删除操作,LinkedList要比ArrayList效率要高。
  • 内存空间占用:LinkedList的元素要更占内存,因为LinkedList的节点除了存储数据,还要存储两个引用,分别指向前一个元素和后一个元素。
  • 线程安全:都不保证线程安全。

ArrayList 和 Vector 的区别是什么?

  • 线程安全:Vector使用Synchronized实现线程同步,是线程安全的,而ArrayList是非线程安全的。
  • 性能:ArrayList的性能要优于Vector。
  • 扩容:ArrayList 和 Vector 都会根据实际的需要动态的调整容量,只不过在 Vector 扩容每次会增加 1 倍,而 ArrayList 只会增加 50%。

Vector类的所有方法都是同步的。可以由两个线程安全地访问一个Vector对象、但是一个线程访问Vector的话代码要在同步操作上耗费大量的时间。

ArrayList不是同步的,所以在不需要保证线程安全时时建议使用ArrayList。

多线程场景下如何使用 ArrayList?

List<String> synchronizedList = Collections.synchronizedList(list);
synchronizedList.add("aaa");
synchronizedList.add("bbb");

for (int i = 0; i < synchronizedList.size(); i++) 
    System.out.println(synchronizedList.get(i));

Set接口

HashSet的实现原理

HashSet 是基于 HashMap 实现的,HashSet的值存放于HashMap的key上,HashMap的value统一为PRESENT(Object对象),因此 HashSet 的实现比较简单,相关 HashSet 的操作,基本上都是直接调用底层 HashMap 的相关方法来完成,HashSet 不允许重复的值。

HashSet与HashMap的区别

HashMapHashSet
实现了Map接口实现Set接口
存储键值对仅存储对象
调用put()向map中添加元素调用add()方法向Set中添加元素
HashMap使用键(Key)计算HashcodeHashSet使用成员对象来计算hashcode值,对于两个对象来说hashcode可能相同,所以equals()方法用来判断对象的相等性,如果两个对象不同的话,那么返回false
HashMap相对于HashSet较快,因为它是使用唯一的键获取对象HashSet较HashMap来说比较慢

Queue

BlockingQueue是什么?

Java.util.concurrent.BlockingQueue是一个队列,在进行检索或移除一个元素的时候,它会等待队列变为非空;当在添加一个元素时,它会等待队列中的可用空间。BlockingQueue接口是Java集合框架的一部分,主要用于实现生产者-消费者模式。我们不需要担心等待生产者有可用的空间,或消费者有可用的对象,因为它都在BlockingQueue的实现类中被处理了。Java提供了集中BlockingQueue的实现,比如ArrayBlockingQueue、LinkedBlockingQueue、PriorityBlockingQueue,、SynchronousQueue等。

在 Queue 中 poll()和 remove()有什么区别?

  • 相同点:都是返回第一个元素,并在队列中删除返回的对象。
  • 不同点:如果没有元素poll()会返回null,而remove()会直接抛出NoSuchElementException异常。

Map

HashMap的实现原理

HashMap概述:HashMap是基于哈希表的Map接口非同步实现。此实现提供了所有可选的映射操作,并允许使用null值和null键。此类不保证映射的顺序。

HashMap的数据结构:链表散列,即数组和链表的结合体(JDK1.8之后加入红黑树)。

HashMap基于Hash算法实现的:

  1. 当我们往HashMap中put元素时,利用key的hashCode重新hash计算出当前对象元素在数组中的下标。
  2. 存储时,如果出现hash值相同的key,此时有两种情况
    1. 如果key相同,则覆盖原始值。
    2. 如果key不同(出现hash冲突),则将当前节点放入链表中。
  3. 获取时,直接找到hash对应的下表,在比较key是否相同,从而找到对应的值。

需要注意JDK1.8中对HashMap的实现做了优化,当链表中的节点数据超过八个之后,该链表会转为红黑树来提高查询效率,从原来的O(n)到O(logn)

HashMap在JDK1.7和JDK1.8中有哪些不同

不同JDK 1.7JDK 1.8
存储结构数组 + 链表数组 + 链表 + 红黑树
初始化方式单独函数:inflateTable()直接集成到了扩容函数resize()
hash值计算方式扰动处理 = 9次扰动 = 4次位运算 + 5次异或运算扰动处理 = 2次扰动 = 1次位运算 + 1次异或运算
存放数据的规则无冲突时,存放数组;冲突时,存放链表无冲突时,存放数组;冲突 & 链表长度 < 8:存放单链表;冲突 & 链表长度 > 8:树化并存放红黑树
插入数据方式头插法(先讲原位置的数据移到后1位,再插入数据到该位置)尾插法(直接插入到链表尾部/红黑树)
扩容后存储位置的计算方式全部按照原来方法进行计算(即hashCode ->> 扰动函数 ->> (h&length-1))按照扩容后的规律计算(即扩容后的位置=原位置 or 原位置 + 旧容量)

具体HashMap源码我们分另一篇文章来总结。

HashMap与HashTable有什么区别?

  1. 线程安全:HashMap是非线程安全的,而HashTable是线程安全的;HashTable 内部的方法基本都经过 synchronized 修饰。
  2. 性能:因为线程安全的问题,HashMap 要比 HashTable 效率高一点。另外,HashTable 基本被淘汰,不要在代码中使用它;
  3. 对Null key 和Null value的支持:HashMap 中,null 可以作为键,这样的键只有一个,可以有一个或多个键所对应的值为 null。但是在 HashTable 中 put 进的键值只要有一个 null,直接抛NullPointerException。
  4. 初始容量大小和每次扩充容量大小的不同:①创建时如果不指定容量初始值,HashTable 默认的初始大小为11,之后每次扩充,容量变为原来的2n+1。HashMap 默认的初始化大小为16。之后每次扩充,容量变为原来的2倍。②创建时如果给定了容量初始值,那么 HashTable 会直接使用你给定的大小,而 HashMap 会将其扩充为2的幂次方大小。
  5. 底层数据结构: JDK1.8 以后的 HashMap 在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为8)时,将链表转化为红黑树,以减少搜索时间。HashTable 没有这样的机制。

HashMap和ConcurrentHashMap的区别

  1. ConcurrentHashMap对整个数组进行了分割分段(Segment),然后在每一个分段上都用lock锁进行保护,相对于HashTable的synchronized锁的粒度更细,并发性更好,而HashMap没有锁机制,不是线程安全的。(JDK1.8之后ConcurrentHashMap启用了一种全新的方式实现,利用CAS算法)。

ConcurrentHashMap会单独放一篇文章来总结。

辅助工具类

如何实现 Array 和 List 之间的转换?

  • Array 转 List: Arrays. asList(array) ;
  • List 转 Array :List 的 toArray() 方法。

comparable 和 comparator的区别?

  • comparable接口实际上是出自java.lang包,它有一个 compareTo(Object obj)方法用来排序。
  • comparator接口实际上是出自 java.util 包,它有一个compare(Object obj1, Object obj2)方法用来排序。

Collection 和 Collections 有什么区别?

  • java.util.Collection 是一个集合接口(集合类的一个顶级接口)。它提供了对集合对象进行基本操作的通用接口方法。Collection接口在Java 类库中有很多具体的实现。Collection接口的意义是为各种具体的集合提供了最大化的统一操作方式,其直接继承接口有List与Set。
  • Collections则是集合类的一个工具类/帮助类,其中提供了一系列静态方法,用于对集合中元素进行排序、搜索以及线程安全等各种操作。

TreeMap 和 TreeSet 在排序时如何比较元素?

TreeSet 要求存放的对象所属的类必须实现 Comparable 接口,该接口提供了比较元素的 compareTo()方法,当插入元素时会回调该方法比较元素的大小。TreeMap 要求存放的键值对映射的键必须实现 Comparable 接口从而根据键对元素进行排序。

java集合(总结,面试使用)(代码片段)

...一个属性是ReentrantLock对象)add方法(会加锁)get方法(未加锁)总结Map1.7HashMapput方法总结(一定要看,不 查看详情

java基础知识总结(代码片段)

...两年了,正好做项目的时候,有个功能,几乎囊括了所有基础知识点,所以把这段自己写的代码记录下来,算是反馈学习成果。 二、代码   1publicclassUdnsAclCommitServiceImplimplementsIUdnsAclCommitService23//创建LOGGE 查看详情

java集合总结:列表和队列(代码片段)

...提供了容器接口的部分实现,方便具体容器类在抽象类的基础上做具体实现。容器类和接口的关系架构图如下:虚线框表示接口,有Collection,List,Set,Queue,Deque和Map。有六个抽象容器类:AbstractCollection:实现了Collection接口,被抽象类... 查看详情

java基础java8stream相关内容的简单总结(代码片段)

文章目录【Java基础】Java8Stream相关内容的简单总结1、创建集合的几个方式2、串行和并行3、遍历4、匹配find/match5、聚合max/min/count6、收集collect(使用Collectors类)7、映射map/flatMap8、筛选filter9、排序sorted10、提取/组合【Java基础】Ja... 查看详情

java基础之多线程总结二(cas和各种常用锁)(代码片段)

CAS在java中,对很多常见的需要加锁的操作进行了封装,例如Atomic开头的一些类,这些类是线程安全的,但是内部却不是用synchronized加锁实现,而是CAS。例如AtomicInteger的’incrementAndGet()'方法最终调用的实际... 查看详情

java研发工程师知识点总结(代码片段)

...工程师知识点总结最近一次更新2017年12月08日大纲一、Java基础(语言、集合框架、OOP、设计模式等)二、Java高级(JavaEE、框架、服务器、工具等)三、多线程和并发四、Java虚拟机五、数据库(Sql、MySQL、Redis等)六、算法与数据结构七、... 查看详情

java基础之容器集合(collection和map)(代码片段)

目录前言一.Collection集合      1.1List集合1.1.1ArrayList集合1.1.2LinkedList集合1.2Set集合1.2.1HashSet集合HashSet集合保证元素唯一性源码分析:1.2.2TreeSet集合比较器排序Comparator的使用: 二.Map集合 2.1Map集合的概述与特点2.2Map集合的获... 查看详情

java基础总结三(泛型异常)(代码片段)

文章目录Java基础总结三(泛型、异常)泛型泛型的创建泛型类泛型接口泛型方法类型擦除泛型的协变与逆变异常异常体系异常处理Java基础总结三(泛型、异常)泛型泛型的创建泛型类我们最常用泛型的地方就是... 查看详情

java基础知识回顾之七-----总结篇(代码片段)

前言在之前Java基础知识回顾中,我们回顾了基础数据类型、修饰符和String、三大特性、集合、多线程和IO。本篇文章则对之前学过的知识进行总结。除了简单的复习之外,还会增加一些相应的理解。基础数据类型基本数据类型主... 查看详情

java基础知识点笔记总结(代码片段)

文章目录1.数组与集合概述2.Collection接口和Map接口集合3.Collection接口集合3.1Collection接口方法3.2集合转数组和数组转集合的一些方法4.Iterator遍历4.1使用Iterator遍历Collection4.2使用foreach循环遍历集合元素5.Collection子接口之一list接口5.1... 查看详情

java基础学习总结(194)——java多线程+list分段完美解决导入等批量更新场景问题(代码片段)

整体流程图整体流程图步骤获取需要进行批量更新的大集合A,对大集合进行拆分操作,分成N个小集合A-1~A-N。开启线程池,针对集合的大小进行调参,对小集合进行批量更新操作,对流程进行控制,控制线程执行顺序。1、按照... 查看详情

java基础学习总结(194)——java多线程+list分段完美解决导入等批量更新场景问题(代码片段)

整体流程图整体流程图步骤获取需要进行批量更新的大集合A,对大集合进行拆分操作,分成N个小集合A-1~A-N。开启线程池,针对集合的大小进行调参,对小集合进行批量更新操作,对流程进行控制,控制线程执行顺序。1、按照... 查看详情

python语言基础—集合的常见操作方法(代码片段)

文章目录一、创建集合二、集合常见操作方法2.1增加数据2.2删除数据2.3查找数据三、总结一、创建集合创建集合使用或set(),但是如果要创建空集合只能使用set(),因为用来创建空字典。s1=10,20,30,40,50print(s1)s2=10,30,20,... 查看详情

java集合面试题看这篇就够了(代码片段)

...题p1【面试题】Java并发篇-10道常见面试题p1【面试题】Java基础篇-常见面试题总结p1【面试题】Java基础篇-常见面试题总结p2【面试题】MySQL常见面试题合集【面试题】Ja 查看详情

java集合容器篇面试题(上)-王者笔记《收藏版》(代码片段)

前期推荐阅读:Java基础知识学习总结(上)Java基础知识学习总结(下)目录一、集合容器概述1.1什么是集合1.2集合的特点1.3集合和数组的区别  1.4使用集合框架的好处1.5常用的集合类有哪些?1.6List,... 查看详情

java基础第二十四天总结——集合

目录:一、Map接口二、Collection工具类/*---------------分割线---------------------*/一、Map接口   Map中的key用Set来存放,不可重复。作为一个Map对象所对应的类,需重写hashCode和equals方法。HashMap是Map接口使用频率最高的实现类... 查看详情

java集合使用注意事项总结(代码片段)

Java集合使用注意事项总结集合判空集合转Map集合遍历集合去重集合转数组数组转集合这篇文章我根据《阿里巴巴Java开发手册》总结了关于集合使用常见的注意事项以及其具体原理。强烈建议小伙伴们多多阅读几遍,避免自... 查看详情

基础总结/集合/collection总结(代码片段)

1.Collection接口Collection是一个根接口,不提供具体的实现,作为子接口的父类使用,由子接口提供实现类1.5之后集合会使用泛型,即规定放入集合中的元素类。如果不设置泛型,则放入集合中元素的数据类型会丢失。都不会变成Ob... 查看详情