Java八股系列——集合框架

Posted _瞳孔

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java八股系列——集合框架相关的知识,希望对你有一定的参考价值。

如果有兴趣了解更多相关内容,欢迎来我的个人网站看看:瞳孔空间

ArrayList和Vector的区别

这两个类都实现了 List 接口(List接口继承了Collection接口),他们都是有序集合,即存储在这两个集合中的元素的位置都是有顺序的,相当于一种动态的数组,我们以后可以按位置索引号取出某个元素,并且其中的数据是允许重复的,这是HashSet 之类的集合的最大不同处,HashSet之类的集合不可以按索引号去检索其中的元素,也不允许有重复的元素(本来题目问的与hashset没有任何关系,但为了说清楚ArrayList 与Vector的功能,我们使用对比方式,更有利于说明问题)。接着才说ArrayList 与Vector的区别,这主要包括两个方面。

  • 同步性:Vector是线程安全的,也就是说是它的方法之间是线程同步的,而ArrayList是线程序不安全的,它的方法之间是线程不同步的。如果只有一个线程会访问到集合,那最好是使用ArrayList,因为它不考虑线程安全,效率会高些;如果有多个线程会访问到集合,那最好是使用Vector,因为不需要我们自己再去考虑和编写线程安全的代码。
  • 数据增长:ArrayList 与Vector都有一个初始的容量大小,当存储进它们里面的元素的个数超过了容量时,就需要增加ArrayList 与Vector 的存储空间,每次要增加存储空间时,不是只增加一个存储单元,而是增加多个存储单元,每次增加的存储单元的个数在内存空间利用与程序效率之间要取得一定的平衡。Vector 默认增长为原来两倍,而ArrayList的增长策略在文档中没有明确规定(从源代码看到的是增长为原来的1.5倍)。ArrayList 与Vector都可以设置初始的空间大小,Vector 还可以设置增长的空间大小,而ArrayList没有提供设置增长空间的方法。

说说 ArrayList,Vector,LinkedList 的存储性能和特性

ArrayList和Vector都是使用数组方式存储数据,此数组元素数大于实际存储的数据以便增加和插入元素,它们都允许直接按序号索引元素,但是插入元素要涉及数组元素移动等内存操作,所以索引数据快而插入数据慢,Vector由于使用了synchronized方法(线程安全)。通常性能上较ArrayList差,而LinkedList使用双向链表实现存储,按序号索引数据需要进行前向或后向遍历,但是插入数据时只需要记录本项的前后项即可,所以插入速度较快。ArrayList在查找时速度快,LinkedList在插入与删除时更具优势。

快速失败 (fail-fast) 和安全失败 (fail-safe) 的区别是什么

lterator的安全失败是基于对底层集合做拷贝,因此,它不受源集合上修改的影响。java.util包下面的所有的集合类都是快速失败的,而 java.util.concurrent包下面的所有的类都是安全失败的。快速失败的迭代器会抛出ConcurrentModificationException异常,而安全失败的迭代器永远不会抛出这样的异常。

HashMap的数据结构

HashMap的源码分析我已经在另一篇博客里面介绍过了,可以看看:HashMap源码分析及常见面试题

heap 和 stack 有什么区别

Java的内存分为两类,一类是栈内存,一类是堆内存。栈内存是指程序进入一个方法时,会为这个方法单独分配一块私属存储空间,用于存储这个方法内部的局部变量,当这个方法结束时,分配给这个方法的栈会释放,这个栈中的变量也将随之释放。堆是与栈作用不同的内存,一般用于存放不放在当前方法栈中的那些数据,例如,使用new 创建的对象都放在堆里,所以,它不会随方法的结束而消失。方法中的局部变量使用final 修饰后,放在堆中,而不是栈中。

HashSet 和 TreeSet 有什么区别

HashSet是由一个hash表来实现的,因此,它的元素是无序的。add(),remove(),contains()。TreeSet是由一个树形的结构来实现的,它里面的元素是有序的。因此,add(),remove(), contains()方法的时间复杂度是O(logn)。

HashSet 的底层实现是什么

通过看源码知道 HashSet 的实现是依赖于 HashMap 的,HashSet 的值都是存储在 HashMap 中的。在 HashSet 的构造法中会初始化一个 HashMap 对象,HashSet 不允许值重复,因此,HashSet 的值是作为 HashMap 的 key 存储在HashMap 中的,当存储的值已经存在时返回 false。

什么是迭代器 (Iterator)

Iterator接口提供了很多对集合元素进行迭代的方法。每一个集合类都包含了可以返回迭代器实例的迭代方法。迭代器可以在迭代的过程中删除底层集合的元素, 但是不可以直接调用集合的 remove(Object Obj) 删除,可以通过迭代器的 remove() 方法删除。

Iterator 和 ListIterator 的区别是什么

  • Iterator 可用来遍历 Set 和 List 集合,但是 ListIterator 只能用来遍历 List。
  • Iterator 对集合只能是前向遍历,ListIterator 既可以前向也可以后向。

ListIterator 实现了 Iterator 接口,并包含其他的功能,比如:增加元素,替换元
素,获取前一个和后一个元素的索引,等等。

Java 集合类框架的最佳实践有哪些

  • 假如元素的大小是固 定的,而且能事先知道,我们就应该用 Array 而不是ArrayList。
  • 有些集合类允许指定初始容量。因此,如果我们能估计出存储的元素的数目,我们可以设置 初始容量来避免重新计算 hash 值或者是扩容。
  • 为了类型安全,可读性和健壮性的原因总是要使用泛型。同时,使用泛型还可以避免运行时的 ClassCastException。
  • 使用 JDK 提供的不变类 (immutable class) 作为 Map 的键可以避免为我们自己的类实现 hashCode()和 equals()方法。
  • 编程的时候接口优于实现。
  • 底层的集合实际上是空的情况下,返回长度是 0 的集合或者是数组,不要返回 null。

Collection 和 Collections 的区别

collection 是集合类的上级接口, 继承与它的接口主要是 set 和 list。

collections 类是针对集合类的一个帮助类. 它提供一系列的静态方法对各种集合的搜索, 排序, 线程安全化等操作。

集合框架中的泛型有什么优点

  1. Java1.5 引入了泛型,所有的集合接口和实现都大量地使用它。
  2. 泛型允许我们为集合提供一个可以容纳的对象类型,因此,如果你添加其它类型的任何元素,它会在编译时报错。
  3. 这避免了在运行时出现 ClassCastException,因为你将会在编译时得到报错信息。
  4. 泛型也使得代码整洁,我们不需要使用显式转换和 instanceOf 操作符。
  5. 它也给运行时带来好处,因为不会产生类型检查的字节码指令。

Java 集合框架的基础接口有哪些

  • Collection 为集合层级的根接口。一个集合代表一组对象,这些对象即为它的元素。Java 平台不提供这个接口任何直接的实现。
  • Set 是一个不能包含重复元素的集合。这个接口对数学集合抽象进行建模,被用来代表集合,就如一副牌。
  • List 是一个有序集合,可以包含重复元素。你可以通过它的索引来访问任何元素。List 更像长度动态变换的数组。
  • Map 是一个将 key 映射到 value 的对象.一个 Map 不能包含重复的 key:每个 key 最多只能映射一个 value。

一些其它的接口有 Queue、Dequeue、SortedSet、SortedMap 和 ListIterator。

Enumeration 和 Iterator 接口的区别

Enumeration 的速度是 Iterator 的两倍,也使用更少的内存。Enumeration 是非常基础的,也满足了基础的需要。但是,与 Enumeration 相比,Iterator 更加安全,因为当一个集合正在被遍历的时候,它会阻止其它线程去修改集合。

迭代器取代了 Java 集合框架中的 Enumeration。迭代器允许调用者从集合中移除元素,而Enumeration 不能做到。为了使它的功能更加清晰,迭代器方法名已经经过改善。

以上是关于Java八股系列——集合框架的主要内容,如果未能解决你的问题,请参考以下文章

Java八股系列——Java基础

Java~大厂面试八股文~强烈推荐视频

数据库八股系列——MySQL

2小时速学大数据编程语言 Scala 秘籍

java八股文面试题(重点)

java八股文面试题(重点)