当前位置: 首页 > news >正文

JAVA面试题大全(二)

1、java 容器都有哪些?

Java中的容器主要可以分为两大类:Collection和Map。

Collection

  1. List:有序的集合,允许重复元素,可以通过索引访问元素。常用的实现类包括:

    • ArrayList:实现了可变大小的数组。它允许所有元素,包括null。ArrayList没有同步。
    • LinkedList:链表实现,提供了在列表的开头和结尾进行操作的便利方法。
    • Vector:和ArrayList类似,但是是同步的,因此是线程安全的。但同步需要花费机器时间,所以Vector的执行效率要低于ArrayList。
    • Stack:栈是Vector的一个子类,它实现了一个后进先出(LIFO)的堆栈。
  2. Set:不允许重复元素的集合,不保证元素的顺序。常用的实现类包括:

    • HashSet:基于哈希表的实现,提供了高效的添加、删除和查找操作。
    • TreeSet:基于红黑树的实现,提供了自然排序或自定义排序的功能。
    • LinkedHashSet:哈希表和链表实现的结合,可以维护元素的插入顺序。

Map

Map提供key到value的映射,一个Map中不能包含相同的key,每个key只能映射一个value。常用的实现类包括:

  1. HashMap:基于哈希表的实现,提供了高效的添加、删除和查找操作。
  2. Hashtable:和HashMap类似,但是是同步的,因此是线程安全的。但同步需要花费机器时间,所以Hashtable的执行效率要低于HashMap。
  3. TreeMap:基于红黑树的实现,提供了自然排序或自定义排序的功能。
  4. LinkedHashMap:哈希表和链表实现的结合,可以维护元素的插入顺序。
  5. ConcurrentHashMap:适用于多线程环境的哈希表实现,提供了高效的并发性能。

此外,Java还提供了其他的容器类,如ArrayDeque(双端队列)、PriorityQueue(优先队列)等,它们分别提供了不同的功能和性能特点。

2、Collection 和 Collections 有什么区别?

Collection是集合的接口,其实现类有List和Set;

Collections是工具类,包含许多有关集合操作的静态多态方法,可以直接使用

3、List、Set、Map 之间的区别是什么?

List、Set和Map在Java中都是集合框架(Collections Framework)的重要部分,但它们之间有明显的区别:

  1. List(列表)

    • 有序性:List中的元素按照它们被添加的顺序进行存储,并且可以通过索引访问每个元素。
    • 可重复性:List允许存储相同的元素多次。也就是说,可以在List中添加重复的元素,并且它们可以保持各自的位置和顺序。
    • 常见的实现类:ArrayList(动态数组实现,适用于查找和随机访问操作)和LinkedList(链表实现,提供了在列表的开头和结尾进行操作的便利方法)。
  2. Set(集合)

    • 无序性:Set集合中的元素是无序的,不能通过下标或者位置来访问元素。遍历Set集合时获取元素的顺序是不确定的。
    • 元素唯一性:Set集合中的元素是唯一的,不会存在重复的元素。当试图添加重复元素时,新元素不会被添加进集合中。
    • 可变性:Set集合的元素可以被增加、删除或者修改,因此是可变的。
    • 哈希表实现:Java中的HashSet是通过哈希表来实现的,因此Set集合的插入、查询和删除操作都具有较快的速度。
    • 线程不安全:Set集合不是线程安全的,如果需要在多线程环境下使用,需要进行同步处理。
    • 支持数学中的集合运算:Set集合支持并集、交集、差集等运算,方便我们进行集合的操作。
  3. Map(映射)

    • 键值对存储:Map中存储的元素是以键值对的形式保存的,每个键值对包含一个键对象和一个值对象,可以根据键对象获取对应的值对象。
    • 键的唯一性:在Map中,每个键对象是唯一的,不能存在相同的键对象,如果向Map中添加一个已经存在的键对象,则会替换掉原有的值对象。
    • 支持null键和null值:HashMap和Hashtable支持null键和null值,TreeMap和ConcurrentHashMap不允许有null键。
    • 无序性:HashMap和Hashtable等散列表实现的Map在存储键值对时并不是以顺序方式存储的,因此不能保证元素的顺序。但如果使用LinkedHashMap,则可以按照插入顺序或访问顺序进行遍历。
    • 高效性:访问和修改Map集合中的元素都非常高效,可以通过哈希表实现,时间复杂度为O(1)。
    • 可以存储不同类型的键值对:Map的键和值可以是任何类型的对象,只要它们能够被正确地哈希和比较。

总的来说,List、Set和Map在Java集合框架中各有其特定的用途和特点。List用于存储有序且可重复的元素,Set用于存储无序且唯一的元素,而Map则用于存储键值对形式的元素,其中键是唯一的。

4、HashMap 和 Hashtable 有什么区别?

HashMap不是线程安全的,HashTable是线程安全的

HashMap允许Null Key和Null Value,HashTable不允许

5、如何决定使用 HashMap 还是 TreeMap?

  1. 性能
    • HashMap通常具有更高的性能,因为它的查找、插入和删除操作的时间复杂度都是O(1)。它通过哈希函数直接定位到数组的某个位置。
    • TreeMap的查找、插入和删除操作的时间复杂度是O(log n),因为它基于红黑树实现。在数据量较大时,HashMap的性能优势会更加明显。
  2. 排序
    • HashMap是无序的,它的存储和遍历顺序与元素的插入顺序无关。它只保证在单线程环境下遍历结果的一致性。
    • TreeMap则是有序的,它可以根据键的自然顺序或自定义的Comparator顺序进行排序和遍历。这使得TreeMap在需要按照一定顺序处理数据的情况下更加适用。
  3. 内存占用
    • TreeMap由于内部采用红黑树数据结构,因此它的内存占用相对较高,比HashMap稍微大一些。
  4. 线程安全性
    • HashMap和TreeMap都是非线程安全的。如果你在多线程环境下使用,需要额外的同步处理。但Java也提供了线程安全的ConcurrentHashMap作为HashMap的替代品。
  5. 具体需求
    • 如果你的应用需要高性能的键值对存储,且不关心元素的顺序,那么HashMap是更好的选择。
    • 如果你的应用需要按照键的排序顺序存储和遍历键值对,那么TreeMap是更好的选择。
  6. 其他特性
    • TreeMap还提供了诸如floorKey()ceilingKey()lowerKey()higherKey()等方法,这些方法可以根据给定的键找到最接近的键,这在某些场景下可能很有用。

6、说一下 HashMap 的实现原理? 

HashMap 的实现原理主要基于数组、链表和红黑树。以下是其具体的实现原理:

  1. 初始化:HashMap 创建一个初始容量为 16 的数组,称为“哈希桶”。
  2. 哈希函数:当添加一个键值对时,HashMap 使用哈希函数来计算该键的哈希码。这个哈希码用来决定该键值对在数组中的索引位置。
  3. 存储键值对:
    • 如果该位置上没有其它键值对,则直接将该键值对存储在该位置上。
    • 如果该位置上已经存在一个或多个键值对(发生了哈希冲突),则遍历链表或树,查找是否已经存在相同的键。
      • 如果存在,则更新对应的值。
      • 如果不存在,则将该键值对添加到链表或树的末尾。
  4. 数据结构调整:
    • 如果链表长度超过了 8,则将链表转化为红黑树,以提高查找性能。
    • 如果树的节点数量少于 6,则将树转换回链表,以节省内存。
  5. 扩容:当数组的使用量达到了负载因子(默认为 0.75)时,HashMap 会自动进行扩容。扩容操作会将数组长度加倍,并重新计算所有键值对的哈希码,然后将它们放入新的哈希桶中。

在 Java 的不同版本中,HashMap 的扩容机制可能有所不同。例如,在 JDK 1.8 中,HashMap 在第一次调用 put 方法时才会初始化数组,并且在扩容过程中会正序遍历原来的数组,并保持链表中节点的相对顺序不变。

总的来说,HashMap 通过哈希函数和哈希桶实现了快速定位元素位置的功能,并通过链表和红黑树解决了哈希冲突的问题。同时,它还具有较好的扩展性和灵活性,可以根据需要自动进行扩容和调整数据结构。

7、说一下 HashSet 的实现原理?

HashSet是基于HashMap实现的,HashSet底层使用HashMap来保存所有元素,因此HashSet的操作相对比较简单,相关HashSet的操作,基本上都是直接调用底层的HashMap的相关方法来完成,HashSet不允许有重复的值,并且元素是无序的

8、ArrayList 和 LinkedList 的区别是什么?

ArrayList的数据结构是动态数组;LinkedList的数据结构是双向链表。

ArrayList比LinkedList在随机访问的时候效率要高,因为LinkedList是线性的数据结构,需要依次往后查找

在非首尾的增删操作,LinkedList要比ArrayList的效率要高,因为ArrayList在操作增删时要影响其他元素的下标

总结:需要频繁读取集合中的元素时,推荐使用ArrayList;插入和删除操作较多时,推荐使用LinkedList

9、如何实现数组和 List 之间的转换?

在Java中,数组(Array)和List之间的转换是常见的操作。

数组转List

你可以使用Arrays.asList()方法将数组转换为List。但是要注意,Arrays.asList()返回的是一个固定大小的列表,不支持addremove操作(会抛出UnsupportedOperationException),因为它返回的实际上是一个Arrays的内部类,这个内部类实现了List接口但没有实现可变大小的方法。

 如果你需要一个可以修改的List,你需要将返回的List转换为一个新的ArrayList或其他可修改的List实现。

int[] intArray = {1, 2, 3, 4, 5};  
List<Integer> intList = Arrays.stream(intArray).boxed().collect(Collectors.toList());  
// 或者对于对象数组  
String[] strArray = {"a", "b", "c"};  
List<String> strList = Arrays.asList(strArray);  // 如果需要修改List,可以转换为ArrayList  
List<String> modifiableStrList = new ArrayList<>(Arrays.asList(strArray));

List转数组

对于List转数组,你可以使用List.toArray()方法,但这个方法默认返回的是Object数组,所以你可能需要指定一个类型参数或者使用toArray(T[] a)方法。

List<String> strList = Arrays.asList("a", "b", "c");  
// 使用无参toArray方法,需要强制类型转换  
String[] strArray1 = (String[]) strList.toArray();  // 使用带类型参数的toArray方法  
String[] strArray2 = strList.toArray(new String[0]);  
// 或者指定数组大小(如果知道大小的话),但通常不需要  
// String[] strArray3 = strList.toArray(new String[strList.size()]);

10、ArrayList 和 Vector 的区别是什么?

相同点:都实现了List接口,都是有序集合

区别:Vector是线程安全的,ArrayList不是线程安全的;

当Vector或ArrayList中的元素超过它的初始大小时,Vector会将容量翻倍,而ArrayList只会将容量扩大50%

11、Array 和 ArrayList 有何区别?

Array类型的变量在声明时必须实例化;ArrayList可以只是先声明;

Array大小是固定的,而ArrayList的大小是动态变化的;

Array可以包含基本类型和对象类型,ArrayList只能包含对象类型

12、怎么确保一个集合不能被修改?

可以使用Collections.unmodifiableCollection(Collection c) 方法创建一个只读集合

这样改变集合的任何操作都会抛出Java. lang. UnsupportedOperationException异常。

13、Iterator 和 ListIterator 有什么区别?

ListIterator有add()方法,可以向List中添加对象,而Iterator不能;

ListIterator有hasPrevious()和previous()方法,可以向前遍历,Iterator不能;

ListIterator可以定位当前的索引位置,nextIndex()和previousIndex()可以实现;

ListIterator可以实现对对象的修改,使用set()实现;而Iterator只能遍历,不能修改

相关文章:

  • Java基础入门day52
  • 网络协议——Modbus-RTU
  • angr使用学习
  • 基于Python flask的豆瓣电影数据分析可视化系统,功能多,LSTM算法+注意力机制实现情感分析,准确率高达85%
  • Flutter 中的 ExpandIcon 小部件:全面指南
  • 2024电工杯数学建模 - 案例:最短时间生产计划安排
  • 线性回归分析
  • 第四十二天 | 背包问题理论
  • 无线通信的穿墙能力主要取决于哪些指标
  • vscode打造舒适的python开发环境
  • Qml:第一个qml程序
  • 前端起dev从110秒减少到7秒, 开发体验大幅提升
  • 使用python对指定文件夹下的pdf文件进行合并
  • .NET8 动态添加定时任务(CRON Expression, Whatever)
  • 大模型关键词
  • 【译】JS基础算法脚本:字符串结尾
  • [微信小程序] 使用ES6特性Class后出现编译异常
  • 5分钟即可掌握的前端高效利器:JavaScript 策略模式
  • Android单元测试 - 几个重要问题
  • const let
  • docker容器内的网络抓包
  • eclipse的离线汉化
  • egg(89)--egg之redis的发布和订阅
  • Hexo+码云+git快速搭建免费的静态Blog
  • JS函数式编程 数组部分风格 ES6版
  • select2 取值 遍历 设置默认值
  • uva 10370 Above Average
  • vue2.0开发聊天程序(四) 完整体验一次Vue开发(下)
  • 从重复到重用
  • 工作手记之html2canvas使用概述
  • 缓存与缓冲
  • 技术胖1-4季视频复习— (看视频笔记)
  • 开年巨制!千人千面回放技术让你“看到”Flutter用户侧问题
  • 力扣(LeetCode)965
  • 每个JavaScript开发人员应阅读的书【1】 - JavaScript: The Good Parts
  • 通过几道题目学习二叉搜索树
  • 小程序01:wepy框架整合iview webapp UI
  • 源码之下无秘密 ── 做最好的 Netty 源码分析教程
  • 翻译 | The Principles of OOD 面向对象设计原则
  • # 执行时间 统计mysql_一文说尽 MySQL 优化原理
  • #LLM入门|Prompt#3.3_存储_Memory
  • #宝哥教你#查看jquery绑定的事件函数
  • #绘制圆心_R语言——绘制一个诚意满满的圆 祝你2021圆圆满满
  • #职场发展#其他
  • #中国IT界的第一本漂流日记 传递IT正能量# 【分享得“IT漂友”勋章】
  • $emit传递多个参数_PPC和MIPS指令集下二进制代码中函数参数个数的识别方法
  • (1)svelte 教程:hello world
  • (31)对象的克隆
  • (C语言)字符分类函数
  • (层次遍历)104. 二叉树的最大深度
  • (规划)24届春招和25届暑假实习路线准备规划
  • (机器学习-深度学习快速入门)第一章第一节:Python环境和数据分析
  • (每日持续更新)jdk api之FileFilter基础、应用、实战
  • (一)Thymeleaf用法——Thymeleaf简介
  • (转)IOS中获取各种文件的目录路径的方法