Collection相关面试题(含答案)
Collection相关面试题
迭代器 Iterator 是什么?Iterator 怎么使用?
提到迭代器 Iterator就要提到迭代器模式,Java 中常用的设计模式之一。用于顺序访问集合对象的元素,无需知道集合对象的底层实现。
Iterator是一个可以被各个集合实现的接口,用于遍历集合里的元素,这样可以避免调用各个集合获取元素的方法。
使用时,map要调用entryset方法。
Iterator iterator = list.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
Iterator iterator=map.entrySet().iterator();
如何边遍历边移除 Collection 中的元素?
这就要用到Iterator了,如果用for遍历的时候删除的话,会报数组越界异常,ArrayIndexOutOfBoundsException,正确的方法应该是
while (iterator.hasNext()){
iterator.remove();
}
为什么Iterator不会产生异常呢
Iterator 是工作在一个独立的线程中,并且拥有一个 mutex 锁。 Iterator 被创建之后会建立一个指向原来对象的单链索引表,当原来的对象数量发生变化时,这个索引表的内容不会同步改变,所以当索引指针往后移动的时候就找不到要迭代的对象,所以按照 fail-fast 原则 Iterator 会马上抛出 java.util.ConcurrentModificationException 异常。
所以 Iterator 在工作的时候是不允许被迭代的对象被改变的。但你可以使用 Iterator 本身的方法 remove() 来删除对象, Iterator.remove() 方法会在删除当前迭代对象的同时维护索引的一致性。
Collections 工具类中的 sort()方法如何比较元素?
public static <T extends Comparable<? super T>> void sort(List<T> list) {
list.sort(null);
}
public static <T> void sort(List<T> list, Comparator<? super T> c) {
list.sort(c);
}
可以看到他有两种方式的排序,一种是继承了Comparable,这种方法就是传入待排序的容器中,然后进行比较,调用了List.sort()方法,这个List.sort()的底层其实调用了Array.sort()方法,Array.sort()的底层有三种排序算法,有个比较耳熟能详的二分排序法,好奇的自己去看吧,我就不多叨叨了。
另一种要传一个Comparator的子类进去,要重写compare() 方法,这样就可以自定义排序了。
ArrayList的优缺点
ArrayList的底层是用数组实现,所以要说优缺点也就只能和数组或者链表进行比较了。
优点:
1.ArrayList可以动态扩容,1.5呗扩容,会将原数组copy过去
2.封装了多个对元素操作的方法
3.索引查询效率更高
缺点:
1.插入删除效率较低
如何实现Array和List之间的相互转换
一种是遍历数组所有元素,add方法添加到List集合中,第二种是用Arrays.asList将数组转成List,第三种就是用Collections.addAll()方法将数组转成List。
List转Array方法就相对少一点,我记得除了遍历元素以外,List有个自带的toArray方法可以将List转成数组。
TreeMap 和 TreeSet 在排序时如何比较元素?
面试官:看来你很了解集合这块知识,那我再问你最后一个问题吧, TreeMap 和 TreeSet 在排序时如何比较元素?
我:好的,TreeSet和TreeMap排序时都需要实现Comparable接口,但TreeSet底层默认参数是Comparator,也就是说TreeSet的排序要实现comparaTo()方法,和且TreeSet底层就是调用了TreeMap的方法,这里体现了组合模式。
而TreeMap要求存放的键值对映射的键必须实现Comparable接口,从而根据键对元素进行排序。
多线程场景下如何使用 ArrayList?
ArrayList是非线程安全的,Vector是线程安全的,但是如果在多线程情形下使用ArrayList如何保证线程安全呢
1.Collections的synchnoizedList可以保证线程安全
List<Object> list =Collections.synchronizedList(new ArrayList<Object>);
2.加锁(synchronized),在add方法上加锁
3.使用线程安全的 CopyOnWriteArrayList 代替
List<Object> list1 = new CopyOnWriteArrayList<Object>();
4.使用ThreadLocal变量确保线程封闭性
ThreadLocal<List<Object>> threadList = new ThreadLocal<List<Object>>() {
@Override
protected List<Object> initialValue() {
return new ArrayList<Object>();
}
};
封闭线程往往是比较安全的, 但由于使用ThreadLocal封装变量,相当于把变量丢进执行线程中去,每new一个新的线程,变量也会new一次,一定程度上会造成性能[内存]损耗,但其执行完毕就销毁的机制使得ThreadLocal变成比较优化的并发解决方案。
Java集合的快速失败机制“fail-fast”是什么?
它是 Java 集合的一种错误检测机制,当多个线程对集合进行结构上的改变操作时,有可能会产生 fail-fast 机制。
举个例子
线程A使用Iterator遍历集合时,线程B修改了集合的机构,不是修改元素,这时就会报ConcurrentModificationException 异常,从而产生 fail-fast 机制。
要想解决就要从Iterator入手,Iterator遍历集合时会产生一个变量modCount,当变量的过程时集合结构改变,modCount就会随之改变,所以只要在modCount上加锁,就能解决fail-fast了
或者直接使用线程安全的集合
最后给你们推荐一本书吧
这是我最近在看的一本书,我觉得很适合在座的各位!
如果答案里可以补充的,请写在评论区
要是有错误,可别放过我,打死我,快点滴!!
啥也不是!!
本文地址:https://blog.csdn.net/qq_42828912/article/details/106791557