Java集合(容器)面试题

2 篇文章 0 订阅

该JAVA面试题转自(https://blog.csdn.net/sufu1065/article/details/88051083),非常感谢博主提供。下面是自己对于面试题的理解与解答,可参考。

JAVA面试题(java基础)1~17题的解答可参考https://blog.csdn.net/yxb09501bin/article/details/94589098
也是自己对于面试题的理解与解答。

Java容器

18.java 容器都有哪些?
在这里插入图片描述

19.Collection 和 Collections 有什么区别?
从上图可以看到,Collection是接口,List和Set是其子接口。
而Collections是算法,提供了对集合进行排序、遍历等多种算法的实现,如

Collections.sort()---排序
Collecitons.reverse()---反转
Collections.shuffle()---混排。

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

  • List

采用线性列表的存储方式,存储的顺序与添加的顺序相同。
List的具体类有ArrayList、LinkedList、Vector

  • Set

不保证元素的顺序,不允许出现重复的元素。
Set的具体类有HashSet、TreeSet

  • Map

采用键-值对的存储方式,键值不允许重复。
Map的具体类有HashMap、TreeMap

21.HashMap 和 Hashtable 有什么区别?
首先说一下两者的相同之处
HashMap和Hashtable都是散列表,都是用来存储键值对(key-value)的,且都是通过“拉链法”解决哈希冲突的。

区别:

  1. HashMap是线程不安全的,Hashtable 是线程安全的。
  2. HashMap继承自AbstractMap,Hashtable继承自Dictionary。
  3. HashMap中key和value可以为null,Hashtable中,key和value都不可以为null。

22.如何决定使用 HashMap 还是 TreeMap?
HashMap和TreeMap都实现了Map类,两者都是用来存储键值对(key-value)的。

  • HshMap就是一个散列表,通过“拉链法”解决哈希冲突的。
  • TreeMap基于红黑树(Red-Black tree)实现,该映射根据其键的自然顺序进行排序,或者根据创建映射时提供的Comparator进行排序,具体取决于使用的构造方法。
  public static void main(String[] args) {
		// TODO Auto-generated method stub	
		Map m1 = new HashMap();
		m1.put("c", "1");
		m1.put("b", "2");
		m1.put("a", "3");

        Map m2 = new TreeMap(); 		
        m2.put("c", "1"); 		
        m2.put("b", "2");
        m2.put("a", "3");
        
        Iterator m1Iter = m1.entrySet().iterator(); 		
        while(m1Iter.hasNext()){ 			
            Map.Entry entry = (Entry) m1Iter.next();
            System.out.println(entry.getValue()); //输出2 1 3 		
        }

        Collection c = m2.values(); 		
        Iterator m2Iter = c.iterator(); 		
        while(m2Iter.hasNext()){
  	        System.out.println(m2Iter.next());//输出3 2 1 		} 	
   
    }

两者虽然存入相同的数据,可是遍历出来出来的结果却完全不一样,注意到TreeMap的结果是按照字母表的顺序进行存储的,HashMap则没有,故在实际开发中,如果数据需要按照一定的顺序进行存储,可以使用TreeMap。

TreeMap是SortedMap接口基于红黑树的实现,该类保证了映射按照升序排列关键字。HashMap是根据键的HashCode 值存储数据,取得数据的顺序是完全随机的,HashMap取值的速度更快

23.说一下 HashMap 的实现原理?

  1. 利用key的hashCode重新hash计算出当前对象的元素在数组中的下标
  2. 存储时,如果出现hash值相同的key,此时有两种情况。(1)如果key相同,则覆盖原始值;(2)如果key不同(出现冲突),则将当前的key-value放入链表中
  3. 获取时,直接找到hash值对应的下标,在进一步判断key是否相同,从而找到对应值。
  4. 理解了以上过程就不难明白HashMap是如何解决hash冲突的问题,核心就是使用了数组的存储方式,然后将冲突的key的对象放入链表中,一旦发现冲突就在链表中做进一步的对比。

24.说一下 HashSet 的实现原理?
与HashMap类似

25.ArrayList 和 LinkedList 的区别是什么?
ArrayList和LinkedList都是实现List接口,对于两者,ArrayList适合快速访问随机访问元素,LinkedList适合快速插入、删除元素。

ArrayList

  1. ArrayList实际上时通过一个数组去保存数据的,当我们构造ArrayList时;若使用默认构造函数,则ArrayList的默认容量大小是10。
  2. 当ArrayList容量不足以容纳全部元素时,ArrayList会重新设置容量:新的容量=“(原始容量x3)/2 + 1”。
  3. ArrayList的克隆函数,即是将全部元素克隆到一个数组中。
  • ArrayList支持三种遍历方式:
  • 通过迭代器遍历(Iterator),效率最低
  • 随机访问,效率最高
  • for遍历循环
 public static void main(String[] args) {
		// TODO Auto-generated method stub	
		List arrList = new ArrayList();
		for(int i=0; i<1000; i++){
			arrList.add(i);
		}
		//通过Iterator遍历
		long IterStartTime = System.currentTimeMillis();
		Iterator listIter = arrList.iterator();
		while(listIter.hasNext()){
			System.out.println(listIter.next());
		}
		long IterEndTime = System.currentTimeMillis();
       //随机访问遍历
		long getStartTime = System.currentTimeMillis();
		for(int i=0; i<arrList.size();i++){
			System.out.print(arrList.get(i));
		}
		long getEndTime = System.currentTimeMillis();
		//for-each循环遍历
		long foreachStartTime = System.currentTimeMillis();
		for(Object it: arrList){
			Integer iter = (Integer) it;
			System.out.println(iter);
		}
		long foreachEndTime = System.currentTimeMillis();


		System.out.println("Iterator:" + (IterEndTime - IterStartTime));
		System.out.println("get(i):" + (getEndTime - getStartTime));
		System.out.println("foreach:" + (foreachEndTime - foreachStartTime));

LinkedList

  1. LinkedList继承AbstractSequentialList,实现了get(int index) set(int index,
    E element) add(int index, E element) remove(int
    index)。这些接口都是随机访问List的

  2. LinkedList 实际上是通过双向链表去实现的。
    它包含一个非常重要的内部类:Entry。Entry是双向链表节点所对应的数据结构,它包括的属性有:当前节点所包含的值,上一个节点,下一个节点

  3. 从LinkedList的实现方式中可以发现,它不存在LinkedList容量不足的问题

  4. LinkedList的克隆函数,即是将全部元素克隆到一个新的LinkedList对象中

  • LinkedList支持以下遍历方式

 public static void main(String[] args) {
		// TODO Auto-generated method stub	
		LinkedList linkedList = new LinkedList();
		for(int i=0; i<1000; i++){
			linkedList.add(i);
		}
	
	//通过Iterator遍历
	Iterator listIter = linkedList.iterator();
	while(listIter.hasNext()){
		System.out.println(listIter.next());
	}
	
	
	//随机访问遍历
	for(int i=0; i<linkedList.size();i++){
		System.out.print(linkedList.get(i));
	}
	
	
	//for-each循环遍历
	for(Object it: linkedList){
		Integer iter = (Integer) it;
		System.out.println(iter);
	}

	//通过pollFirst()遍历
	while(linkedList.pollFirst() != null){
		System.out.println(linkedList.pollFirst());
	}
	
	//通过pollLast()遍历
	while(linkedList.pollLast() != null){
		System.out.println(linkedList.pollLast());
	}
	

}

26.如何实现数组和 List 之间的转换?

List转数组

public static void main(String[] args) {
		// TODO Auto-generated method stub	
		//List转数组
		List<Integer> list = new ArrayList();
		for(int i=0; i<10; i++){
			list.add(i);
		}
	
	//第一种方式,强转
	Integer[] arr1 = (Integer[]) list.toArray();
	
	//第二种方式
	int listLen = list.size();
	Integer[] arr2 = new Integer[listLen]; 
	list.toArray(arr1);
	
	//第三种方式
	Integer[] arr3 = (Integer[])list.toArray(new Integer[0]);
	
}

数组转List

public static void main(String[] args) {
		// TODO Auto-generated method stub	
		//数组转List
		Integer[] arr = new Integer[10];
	
	//第一种方法,Arrays.asList()
	List<Integer> list1 = Arrays.asList(arr);
	
	//第二种方法,Collections.addAll()
	List<Integer> list2 = new ArrayList();
	Collections.addAll(list2, arr);
	
	//第三种方法
	List<Integer> list3 = new ArrayList();
	for(int i=0;i<arr.length;i++){
		list3.add(arr[i]);
	}
}

27.ArrayList 和 Vector 的区别是什么?
两者都实现了List接口,最主要的区别在于Vector为线程安全,而ArrayList为非线程安全。

28.Array 和 ArrayList 有何区别?
Array是数组,而ArrayList是Array的增强版,下面将从以下几个方面谈一下两者的
区别:

  • (1)长度是否可变

     Array的`长度不可变`
     ArrayList`长度可变`,动态增长
    
  • (2)存储的数据类型

     Array只能存储`相同数据类型`的数据
     ArrayList可以存储`不同数据类型`的数据
    
  • (3)方法

     ArrayList的方法比Array的方法多
    
  • (4)两者互相转换

     参考问题26
    

29.在 Queue 中 poll()和 remove()有什么区别?
Queue 中 poll()和 remove()都是移除并返回队头元素。
两者的区别如下:
remove函数,当队列为空时,会抛出下面的异常。
在这里插入图片描述
而poll()函数在队列为空时,返回null
在这里插入图片描述
30.哪些集合类是线程安全的?

  • 常用的集合(线程安全):

     List中的Vector
     Map中的Hashtable
    
  • 常见的并发集合(线程安全):

     ConcurrentHashMap:线程安全的HashMap的实现 
     CopyOnWriteArrayList:线程安全且在读操作时无锁的ArrayList 
     CopyOnWriteArraySet:基于CopyOnWriteArrayList,不添加重复元素 
     ArrayBlockingQueue:基于数组、先进先出、线程安全,可实现指定时间的阻塞读写,并且容量可以限制 
     LinkedBlockingQueue:基于链表实现,读写各用一把锁,在高并发读写操作都多的情况下,性能优于ArrayBlockingQueue
    

31.迭代器 Iterator 是什么?

Java采用了迭代器来为各种容器提供公共的操作接口,这样使得对容器的遍历操作与其具体的底层实现隔离,达到解耦的效果。

32.Iterator 怎么使用?有什么特点?

在Iterator接口中定义了三个方法: 
在这里插入图片描述
eg:

public static void main(String[] args) {
		// TODO Auto-generated method stub	
		List list = new ArrayList();
		for(int i=0; i<10; i++){
			list.add(i + "-a");
		}
	
	Iterator listIter = list.iterator();
	while(listIter.hasNext()){
		String str = (String) listIter.next();
		System.out.println(str);
	}
}

33.Iterator 和 ListIterator 有什么区别?
从上面的题目中可以看到,Iterator只提供了删除元素的方法remove();
而ListIterator接口继承了Iterator,允许程序员按照任一方向遍历列表,迭代期间修改列表,并获得迭代器在列表中的当前位置。
在这里插入图片描述

34.怎么确保一个集合不能被修改?
利用Collections提供的方法
在这里插入图片描述

上面是自己对于这些面试题的理解,其中在查找资料的过程中,有参考以下博文:
1、https://www.cnblogs.com/liulin1187740947/p/9164870.htm
2、https://blog.csdn.net/qq_41097354/article/details/90403953
非常感谢!如博文中有错误的地方,还请大家不吝赐教。

l

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值