当前位置: 首页 > 后端技术 > Java

Java面试题总结(合集)

时间:2023-04-01 16:38:56 Java

合集1.List、Map、Set这三个接口访问元素时,各自有什么特点?列表访问具有特定索引的元素,并且可以有重复的元素。Set不能存储重复的元素(使用对象的equals()方法来区分元素是否重复)。Map保存的是键值对(key-valuepair)映射关系,映射关系可以是一对一,也可以是多对一。Set和Map容器都有基于哈希存储和排序树的两个实现版本。基于哈希存储的版本理论上访问时间复杂度为O(1),而基于排序树版本的实现是插入或删除元素。会根据元素或者元素的key构建排序树,达到排序去重的效果。2、ArrayList、Vector、LinkedList的存储性能和特点ArrayList和Vector都是使用数组来存储数据。该数组的元素个数大于实际存储的添加和插入元素的数据。它们都允许直接通过序号索引元素,但是插入元素会涉及到数组元素移动等内存操作,所以查询数据快而插入数据慢。Vector中的方法加上了synchronized修饰,所以Vector是线程安全的容器,但是性能比ArrayList差,所以在Java中已经是遗留物了。容器。LinkedList采用双向链表进行存储(通过附加引用将内存中分散的内存单元关联起来,形成一个可以按序号索引的线性结构。与数组的连续存储方式相比,这种链式存储方式具有更高的memoryutilizationHigher),按序号索引数据需要向前或向后遍历,但插入数据时只需要记录此项的前后项,因此插入速度较快。Vector是遗留容器(Java早期版本提供的容器,另外,Hashtable、Dictionary、BitSet、Stack、Properties都是遗留容器),不推荐使用,但是因为ArrayList和LinkedListed都是非线程安全的,如果遇到多个线程操作同一个容器的场景,可以使用工具类Collections中的synchronizedList方法将其转化为线程安全的容器再使用(这就是装饰模式的应用),将现有对象传递给另一个在类的构造函数中创建新对象以增强实现)。3.List、Set、Map是否继承自Collection接口List,Set是,Map否。Map是一个键值对映射容器,与List、Set有明显区别。Set存储的是分散的元素,不允许有重复的元素(数学中的集合也是如此)。List是线性结构的容器,适用于通过索引访问元素的情况。4.Collection和Collections的区别Collection是集合类的上层接口。它的继承和接口主要有Set和List。Collections是集合类的辅助类。它提供了一系列静态方法来实现各种集合的查找、排序、线程安全等操作。5.ArrayList和LinkedListArrayList和LinkedList都实现了List接口。它们有以下区别:ArrayList是一个基于索引的数据接口,它的底层是一个数组。它可以对具有O(1)时间复杂度的元素执行随机访问。相应地,LinkedList以元素列表的形式存储其数据,每个元素与其上一个和下一个元素链接。在这种情况下,查找元素的时间复杂度为O(n)。与ArrayList相比,LinkedList的插入、添加、删除操作更快,因为当元素添加到集合中的任意位置时,不需要像数组那样重新计算大小或更新索引。LinkedList比ArrayList占用更多的内存,因为LinkedList为每个节点存储了两个引用,一个指向前一个元素,一个指向下一个元素。6、HashMap和HashtableHashMap和Hashtable都实现了Map接口,所以很多特性非常相似。但是,它们有以下区别:HashMap允许键和值都为null,而Hashtable不允许键或值为null。Hashtable是同步的,而HashMap不是。所以HashMap更适合单线程环境,而Hashtable适合多线程环境。HashMap提供了一个可以被应用程序迭代的键集合,因此,HashMap是快速失败的。另一方面,Hashtable提供了键的枚举(Enumeration)。Hashtable通常被认为是遗留类。7、快速失败(fail-fast)和安全失败(fail-safe)快速失败(fail-fast)用迭代器遍历一个集合对象时,如果集合对象的内容被修改(增删改查等),modification),并发修改异常将被抛出。原理:迭代器遍历时直接访问集合的内容,遍历时使用一个modCount变量。如果在遍历过程中集合的内容发生变化,则modCount的值也会发生变化。每当迭代器在遍历下一个元素之前使用hashNext()/next()时,它会检查modCount变量是否为预期的modCount值,如果是则返回遍历;否则,抛出异常并终止遍历。注意:这里抛出的异常是检测modCount!=expectedmodCount这个条件。如果在集合发生变化时修改后的modCount值只是设置为expectedmodCount值,则不会抛出异常。因此,您不能根据是否抛出此异常来编写并发操作。此异常仅建议用于检测并发修改错误。场景:java.util包下的集合类failfast,多线程下不能并发修改(迭代修改)。安全失效(fail-safe)是一种采用安全失效机制的集合容器。遍历时,不直接访问集合内容,而是先复制原始集合内容,在复制的集合上遍历。原理:由于迭代时遍历的是原集合的副本,遍历过程中对原集合所做的修改无法被迭代器检测到,因此不会触发ConcurrentModificationException。缺点:复制内容的好处是避免了ConcurrentModificationException,但同样,迭代器无法访问修改后的内容,即迭代器遍历的是开始遍历那一刻得到的集合的副本。在遍历过程中,原始迭代器不知道集合的变化。场景:java.util.concurrent包下的容器是safetofail,可以在多线程下并发使用和修改。Iterator的故障保护基于制作底层集合的副本,因此它不受源集合修改的影响。java.util包下的所有集合类都是fail-fast,java.util.concurrent包下的所有类都是fail-safe。快速失败迭代器将抛出ConcurrentModificationException,而失败安全迭代器永远不会抛出此类异常。8、Iterator和ListIterator的区别Iterator可以用来遍历Set和List集合,而ListIterator只能用来遍历List。Iterator只能向前遍历集合,ListIterator可以向前也可以向后。ListIterator实现了Iterator接口并包含了其他功能,例如:添加元素、替换元素、获取上一个元素和下一个元素的索引等。9.什么是迭代器?Iterator提供了统一的接口,以统一的方式遍历集合元素。Collection接口实现了Iterable接口。每个集合通过实现Iterable接口中的iterator()方法返回一个Iterator接口的实例,然后迭代集合中的元素。手术。注意:在迭代元素时,不能通过collection方法删除元素,否则会抛出ConcurrentModificationException。但是,您可以通过Iterator接口中的remove()方法删除它们。10、为什么集合类没有实现Cloneable和Serializable接口克隆?克隆(cloning)或序列化(serialization)的语义和意义与具体实现有关。因此,如何克隆或序列化,应该由集合类的具体实现类来决定。实现Serializable序列化的作用:将对象的状态保存在存储介质中,以便以后可以重写创建一个完全相同的副本;按值将对象从一个应用程序域发送到另一个应用程序域。实现Serializable接口的作用是将对象保存到字节流中,然后再恢复。所以你想如果你的对象没有被序列化,怎么通过网络传输呢?对于网络传输,必须要转换成字节流,所以在分布式应用中,就得实现序列化。如果您不需要分布式应用程序,则无需实现序列化。11、ConcurrentHashMapConcurrentHashMap是HashMap的线程安全版本,支持高效并发。在默认的理想状态下,ConcurrentHashMap可以支持16个线程进行任意数量的线程并发写操作和读操作。ConcurrentHashMap类包含两个静态内部类HashEntry和Segment。HashEntry用于封装映射表的key/value对;Segment用来充当一把锁,每个Segment对象守护着整个哈希映射表的几个bucket。每个桶都是一个由多个HashEntry对象链接的链表。ConcurrentHashMap实例包含多个Segment对象的数组。HashEntry用于封装哈希映射中的键值对。在HashEntry类中,key、hash和next字段都声明为final,value字段声明为volatile。staticfinalclassHashEntry{finalKkey;//将键声明为最终类型finalinthash;//将哈希值声明为最终类型volatileV值;//将值声明为volatile类型finalHashEntrynext;//将next声明为最终HashEntry(Kkey,inthash,HashEntrynext,Vvalue){this.key=key;this.hash=hash;这个.下一个=下一个;这。价值=价值;}}在ConcurrentHashMap中,如果在散列过程中发生了“碰撞”,则会采用“分离链接法”来处理“碰撞”:将“碰撞”的HashEntry对象链接成一个链表。由于HashEntry的next字段是final的,新节点只能插入到链表的头部。下图是在一个空桶中依次插入三个HashEntry对象A、B、C后的结构图:图1.插??入三个节点后的桶结构图:在ConcurrentHashMap中,如果哈希时发生“碰撞”,会使用“分离链接法”来处理“碰撞”:将“碰撞”的HashEntry对象链接成一个链表。由于HashEntry的next字段是final的,新节点只能插入到链表的头部。下图是在空桶中依次插入三个HashEntry对象A、B、C后的结构图:注:由于只能插入表头,所以链表中节点的顺序与插入。Segment类继承自ReentrantLock类,这样Segment对象就可以起到锁的作用。每个Segment对象用来守卫它包含的几个桶(在成员对象表中)。concurrenthashmap的优点和1.7与1.8的区别是什么?Concurrenthashmap是线程安全的。1.7在jdk1.7中使用Segment+HashEntry实现,在Segment上加锁。1.7size的计算是先用解锁的方法连续计算元素个数,最多计算3次:1.如果前后两次计算的结果相同,说明计算的个数元素准确;2.如果前后计算结果如果两次计算结果不一样,则锁住每一段,重新计算元素个数;在1.8中,放弃了臃肿的Segment设计,取而代之的是Node+CAS+Synchronized,保证并发安全。1.8一个volatile变量baseCount用来记录元素个数。当插入新数据或删除数据时,会通过addCount()方法更新baseCount。通过累加baseCount和CounterCell数组中的个数,可以得到元素总数Number;12.TreeMapTreeMap是一个有序的key-value集合,基于红黑树的NavigableMap实现。映射根据其键的自然顺序进行排序,或者根据创建映射时提供的比较器进行排序,具体取决于所使用的构造函数。TreeMap的特点:根节点为黑色每个节点只能为红色或黑色每个叶子节点(NIL节点,空节点)为黑色。如果一个节点是红色的,那么它的两个子节点都是黑色的,也就是说一条路径上不能出现两个红色节点。从任何节点到其每个叶子的所有路径都包含相同数量的黑色节点。13、ArrayList会越界吗?ArrayList实现了一种基于动态数组的数据结构,而LinkedList是一种基于链表的数据结构。对于随机访问get和set,ArrayList优于LinkedList,因为LinkedList需要移动指针;ArrayList并发add()可能会出现数组下标越界异常。14、为什么HashMap的容量是2^n?默认加载因子为0.75。2^n是为了让散列更均匀。比如在极端情况下,在数组中的一个下标中进行hash,那么hashmap就会将O(1)的复杂度退化为O(n)。如果hashMap的key是自定义类,则必须重写hashcode()和equals()