1 Star 0 Fork 31

moyu3390 / Ebooks_1

forked from Java精选 / Ebooks 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
最新面试题2021年Java集合面试题及答案汇总.md 11.88 KB
一键复制 编辑 原始数据 按行查看 历史

最新面试题2021年Java集合面试题及答案汇总

全部面试题答案,更新日期:01月30日,直接下载吧!

下载链接:高清500+份面试题资料及电子书,累计 10000+ 页大厂面试题 PDF

Java 集合

题1:Java 中求单链表中节点的个数?

Java中计算单链表中节点的个数需要注意检查链表是否为空。时间复杂度为O(n)。

核心代码:

// 方法:获取单链表的长度
public int getLength(Node head) {
	if (head == null) {
		return 0;
	}

	int length = 0;
	Node current = head;
	while (current != null) {
		length++;
		current = current.next;
	}

	return length;
}

题2:Java 中如何合并两个有序单链表后依然有序?

举例:

链表1: 1->2->3->4 链表2: 2->3->4->5 合并后: 1->2->2->3->3->4->4->5

解题思路

逐一比较链表1和链表2,类似于归并排序。尤其要注意两个链表都为空和其中一个为空的情况。只需要O(1)的空间。时间复杂度为O (max(len1,len2))

此部分代码借助“Java精选面试题”微信小程序中“Java 中如何单链表的创建和遍历”试题的代码,代码实现:

public Node head;
public Node current;

class Node {
	int data; // 数据域
	Node next;// 指针域

	public Node(int data) {
		this.data = data;
	}
}
// 两个参数代表的是两个链表的头结点
public Node mergeLinkList(Node head1, Node head2) {

	if (head1 == null && head2 == null) { // 如果两个链表都为空
		return null;
	}
	if (head1 == null) {
		return head2;
	}
	if (head2 == null) {
		return head1;
	}

	Node head; // 新链表的头结点
	Node current; // current结点指向新链表
	// 一开始,我们让current结点指向head1和head2中较小的数据,得到head结点
	if (head1.data < head2.data) {
		head = head1;
		current = head1;
		head1 = head1.next;
	} else {
		head = head2;
		current = head2;
		head2 = head2.next;
	}

	while (head1 != null && head2 != null) {
		if (head1.data < head2.data) {
			current.next = head1; // 新链表中,current指针的下一个结点对应较小的那个数据
			current = current.next; // current指针下移
			head1 = head1.next;
		} else {
			current.next = head2;
			current = current.next;
			head2 = head2.next;
		}
	}

	// 合并剩余的元素
	if (head1 != null) { // 说明链表2遍历完了,是空的
		current.next = head1;
	}

	if (head2 != null) { // 说明链表1遍历完了,是空的
		current.next = head2;
	}

	return head;
}

测试代码:

public static void main(String[] args) {
	LinkList list1 = new LinkList();
	LinkList list2 = new LinkList();
	// 向LinkList中添加数据
	for (int i = 0; i < 4; i++) {
		list1.add(i);
	}
	for (int i = 3; i < 8; i++) {
		list2.add(i);
	}
	LinkList list3 = new LinkList();
	list3.head = list3.mergeLinkList(list1.head, list2.head); // 将list1和list2合并,存放到list3中

	list3.print(list3.head);// 从head节点开始遍历输出
}

执行结果

0
1
2
3
3
4
5
6
7

题3:HashMap 中一般使用什么类型元素作为 Key?

HashMap一般采用String、Integer 等类作为key、因为这些类底层已经重写了hashcode、equals方法,用的是final修饰类在多线程情况下相对安全。

题4:HashMap 是怎么扩容的?

当HashMap中元素个数超过数组大小*loadFactor时,需进行数组扩容。

loadFactor默认值为0.75,默认情况下,数组大小为16,HashMap中元素个数超过16 * 0.75=12的时,就把数组的大小扩展为2*16=32,即扩大一倍,然后重新计算每个元素在数组中的位置,而这是一个非常消耗性能的操作,所以能够预选知道HashMap中元素的个数,应该预设数组的大小,可以有效的提高HashMap的性能。

假设有1000个元素new HashMap(1000),理论上来讲new HashMap(1024)更合适,不过上面已经提过即使是1000个元素,HashMap也会自动设置为1024。但是new HashMap(1024),而0.75*1024 <1000, 为了可以0.75 * size >1000,必须new HashMap(2048),避免了resize的问题。

总结:

添加元素时会检查容器当前元素个数。当HashMap的容量值超过临界值(默认16 * 0.75=12)时扩容。HashMap将会重新扩容到下一个2的指数幂(16->32->64)。调用resize方法,定义长度为新长度(32)的数组,然后对原数组数据进行再Hash。注意的是这个过程比较损耗性能。

题5:Java 迭代器 Iterator 是什么?

迭代器模式是Java中常用的设计模式之一,主要用于顺序访问集合对象的元素,无需知道集合对象的底层实现。

Iterator是可以遍历任何Collection集合的对象,为各种容器提供了公共的操作接口,隔离对容器的遍历操作和底层实现,从而解耦。

Collection集合中使用迭代器方法来获取迭代器实例,迭代器取代了Java集合框架中Enumeration。迭代器允许调用者在迭代过程中移除元素。

Iterator的缺点是增加新的集合类需要对应增加新的迭代器类,迭代器类与集合类成对增加。

题6:Java 中如何确保一个集合不能被修改?

可以使用Collections包下的unmodifiableMap()方法,通过这个方法返回的map是不可以修改的。这样改变集合的任何操作都会抛出Java.lang.UnsupportedOperationException异常。

Collections包也提供了对list和set集合的方法。

Collections.unmodifiableList(List)
Collections.unmodifiableSet(Set)

也可以使用Collections.unmodifiableCollection(Collection c)方法来创建一个只读集合,这样改变集合的任何操作都会抛出Java.lang.UnsupportedOperationException异常。

示例代码:

List<String> list = new ArrayList<>();
list. add("微信公众号");
Collection<String> unmlist = Collections.unmodifiableCollection(list);
unmlist.add("Java精选"); // 运行时此行报错
System.out.println(list.size());

题7:Java 中如何创建和遍历单链表?

public class LinkList {
	public Node head;
	public Node current;

	//方法:向链表中添加数据  
	public void add(int data) {
		// 判断链表为空
		if (head == null) {// 如果头结点为空,说明这个链表还没有创建,那就把新的结点赋给头结点
			head = new Node(data);
			current = head;
		} else {
			// 创建新的结点,放在当前节点的后面(把新的结点合链表进行关联)
			current.next = new Node(data);
			// 把链表的当前索引向后移动一位
			current = current.next; // 此步操作完成之后,current结点指向新添加的那个结点
		}
	}

	//方法:遍历链表(打印输出链表。方法的参数表示从节点node开始进行遍历  
	public void print(Node node) {
		if (node == null) {
			return;
		}

		current = node;
		while (current != null) {
			System.out.println(current.data);
			current = current.next;
		}
	}

	class Node {
		//注:此处的两个成员变量权限不能为private,因为private的权限是仅对本类访问。  
		int data; // 数据域
		Node next;// 指针域

		public Node(int data) {
			this.data = data;
		}
	}

	public static void main(String[] args) {
		LinkList list = new LinkList();
		//向LinkList中添加数据  
		for (int i = 0; i < 10; i++) {
			list.add(i);
		}

		list.print(list.head);// 从head节点开始遍历输出
	}

}

执行结果

0
1
2
3
4
5
6
7
8
9

查看上述代码,Node节点采用的是内部类来表示。使用内部类的最大好处是可以和外部类进行私有操作的互相访问。

内部类访问的特点是:内部类可以直接访问外部类的成员,包括私有;外部类要访问内部类的成员,必须先创建对象。

为了方便添加和遍历的操作,在LinkList类中添加一个成员变量current,用来表示当前节点的索引。

遍历链表的方法中,参数node表示从node节点开始遍历,不一定要从head节点遍历。

题8:Java 中遍历 List 集合都有哪些方式?

List<String> list = new ArrayList<>();

for (int i = 0; i < list.size(); i++) {
	System.out.println(list.get(i));
}

//使用for-each循环
for(String obj : list){
	System.out.println(obj);
}

//使用迭代器 iterator
Iterator<String> it = list.iterator();
while(it.hasNext()){
  String obj = it.next();
  System.out.println(obj);
}

遍历List集合时使用迭代器方式线程安全,可以保障遍历的集合元素不被修改,否则抛出异常ConcurrentModificationException。

题9:Java 泛型有什么优点?

JDK1.5版本引入了泛型,所有的集合接口和实现都大量地使用它。

类型安全,提供编译期间的类型检测。泛型允许为集合提供一个可以容纳的对象类型,如果添加其它类型的任何元素,它会在编译时报错,避免运行时出现异常ClassCastException。

泛型前后兼容。

泛化代码,代码可以更多的重复利用,泛型使得代码整洁,不需要使用显式转换和instanceOf操作符。

泛型性能比较高,用GJ(泛型Java)编写的代码可以为Java编译器和虚拟机带来更多的类型信息,这些信息对Java程序做进一步优化提供条件。

题10:Set 为什么是无序的?

Set系列集合添加元素无序的根本原因是底层采用哈希表存储元素。

JDK1.8以下版本:哈希表 = 数组 + 链表 + (哈希算法)

JDK1.8及以上版本:哈希表 = 数组 + 链表 + 红黑树 + (哈希算法)

当链表长度超过阈值(8)时,将链表转换为红黑树,这样大大减少了查找时间。

题11:iterator-和-enumeration-接口有哪些区别

题12:为什么不直接将key作为哈希值而是与高16位做异或运算

题13:collection-和-collections-有什么区别

题14:comparable-和-comparator有什么区别

题15:java-中两个对象-hashcode-相等会产生什么问题-

题16:arrays.aslist()-有什么使用限制

题17:java-中迭代集合如何避免-concurrentmodificationexception

题18:hashmap-和-hashtable-有什么区别

题19:java-中-list-集合如何排序

题20:arraylist-和-copyonwritearraylist-有什么区别

题21:java-中什么是-fail-fast

题22:iterater-和-listiterator-都有哪些区别

题23:vector-和-arraylist-有什么区别和联系

题24:hashmap-集合如何按-value-值排序

题25:java-中-unsupportedoperationexception-是什么

大厂面试题

大厂面试题

大厂面试题

Java
1
https://gitee.com/moyu3390/ebooks_1.git
git@gitee.com:moyu3390/ebooks_1.git
moyu3390
ebooks_1
Ebooks_1
master

搜索帮助

53164aa7 5694891 3bd8fe86 5694891