• Java面试题


    一、Java集合面试题

    1.什么是fail fast?

    fail-fast的字面意思是“快速失败”。当我们在遍历集合元素的时候,经常会使用迭代器,但在迭代器遍历元素的过程中,如果集合的结构被改变的话,就会抛出异常,防止继续遍历。这就是所谓的快速失败机制。

    意思就是说:迭代器的快速失败行为是不一定能够得到保证的,一般来说,存在非同步的并发修改时,不可能做出任何坚决的保证的。但是快速失败迭代器会做出最大的努力来抛出ConcurrentModificationException。因此,编写依赖于此异常的程序的做法是不正确的。正确的做法应该是:迭代器的快速失败行为应该仅用于检测程序中的bug.

    稍微总结下:fail-fast,即快速失败机制,它是java集合中的一种错误检测机制,当多个线程(单个线程也是可以滴),在结构上对集合进行改变时,就有可能会产生fail-fast机制。

    解决方法:

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

    2.什么是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()转换成线程同步。

    3. 迭代器 Iterator 是什么?

    Iterator模式用同一种逻辑来遍历集合。它可以把访问逻辑从不同类型的集合类中抽象出来,不需要了解集合内部实现便可以遍历集合元素,统一使用 Iterator 提供的接口去遍历。它的特点是更加安全,因为它可以保证,在当前遍历的集合元素被更改的时候,就会抛出 ConcurrentModificationException 异常。

    public interface Collection<E> extends Iterable<E> {
    	Iterator<E> iterator();
    }
    
    • 1
    • 2
    • 3

    主要有三个方法:hasNext()、next()和remove()


    著作权归大彬所有 原文链接:https://www.topjavaer.cn/java/java-collection.html

    4. Iterator 和 ListIterator 有什么区别?

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

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

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

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

    ListIterator 是 Iterator的增强版。

    • ListIterator遍历可以是逆向的,因为有previous()和hasPrevious()方法,而Iterator不可以。
    • ListIterator有add()方法,可以向List添加对象,而Iterator却不能。
    • ListIterator可以定位当前的索引位置,因为有nextIndex()和previousIndex()方法,而Iterator不可以。
    • ListIterator可以实现对象的修改,set()方法可以实现。Iierator仅能遍历,不能修改。
    • ListIterator只能用于遍历List及其子类,Iterator可用来遍历所有集合

    5.如何让一个集合不能被修改?

    可以采用Collections包下的unmodifiableMap/unmodifiableList/unmodifiableSet方法,通过这个方法返回的集合,是不可以修改的。如果修改的话,会抛出 java.lang.UnsupportedOperationException异常。

    List<String> list = new ArrayList<>();
    list.add("x");
    Collection<String> clist = Collections.unmodifiableCollection(list);
    clist.add("y"); // 运行时此行报错
    System.out.println(list. size());
    
    • 1
    • 2
    • 3
    • 4
    • 5

    对于List/Set/Map集合,Collections包都有相应的支持。

    那使用final关键字进行修饰可以实现吗?

    答案是不可以。

    final关键字修饰的成员变量如果是是引用类型的话,则表示这个引用的地址值是不能改变的,但是这个引用所指向的对象里面的内容还是可以改变的。

    而集合类都是引用类型,用final修饰的话,集合里面的内容还是可以修改的。

  • 相关阅读:
    Windows Service Wrapper 一个将可执行文件封装为windows服务的工具
    体育世界杂志体育世界杂志社体育世界编辑部2022年第4期目录
    音视频领域的未来发展方向展望
    【手写一个Tomcat】SimpleTomcat-01
    一盏茶的功夫帮你彻底搞懂JavaScript异步编程从回调地狱到async/await
    人工智能-深度学习之延后初始化
    [C]精炼分析状态机FSM
    PgSQL-内核特性-TupleTableSlotOps
    ArcGIS学习(十四)OD分析
    用DIV+CSS技术设计的体育主题网站(足球介绍)
  • 原文地址:https://blog.csdn.net/Afu1021/article/details/133593725