2022Java面试题大全,附答案,最新整理

1. 遍历ArrayList时如何正确移除一个元素

错误写法示例一:

public static void remove(ArrayList<String> list) { for (int i = 0; i < list.size(); i++) { String s = list.get(i); if (s.equals("bb")) { list.remove(s); } } }

错误写法示例二:

public static void remove(ArrayList<String> list) { for (String s : list) { if (s.equals("bb")) { list.remove(s); } } }

要分析产生上述错误现象的原因唯有翻一翻jdk的ArrayList源码,先看下ArrayList中的remove方法(注意ArrayList中的remove有两个同名方法,只是入参不同,这里看的是入参为Object的remove方法)是怎么实现的:

public boolean remove(Object o) { if (o == null) { for (int index = 0; index < size; index++) if (elementData[index] == null) { fastRemove(index); return true; } } else { for (int index = 0; index < size; index++) if (o.equals(elementData[index])) { fastRemove(index); return true; } } return false; }

按一般执行路径会走到else路径下最终调用faseRemove方法:

private void fastRemove(int index) { modCount++; int numMoved = size - index - 1; if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); elementData[--size] = null; // Let gc do its work }

可以看到会执行System.arraycopy方法,导致删除元素时涉及到数组元素的移动。针对错误写法一,在遍历第二个元素字符串bb时因为符合删除条件,所以将该元素从数组中删除,并且将后一个元素移动(也是字符串bb)至当前位置,导致下一次循环遍历时后一个字符串bb并没有遍历到,所以无法删除。 针对这种情况可以倒序删除的方式来避免:

public static void remove(ArrayList<String> list) { for (int i = list.size() - 1; i >= 0; i--) { String s = list.get(i); if (s.equals("bb")) { list.remove(s); } } }

因为数组倒序遍历时即使发生元素删除也不影响后序元素遍历。

而错误二产生的原因却是foreach写法是对实际的Iterable、hasNext、next方法的简写,问题同样处在上文的fastRemove方法中,可以看到第一行把modCount变量的值加一,但在ArrayList返回的迭代器(该代码在其父类AbstractList中):

public Iterator<E> iterator() { return new Itr(); }

这里返回的是AbstractList类内部的迭代器实现private class Itr implements Iterator,看这个类的next方法:

public E next() { checkForComodification(); try { E next = get(cursor); lastRet = cursor++; return next; } catch (IndexOutOfBoundsException e) { checkForComodification(); throw new NoSuchElementException(); } }

第一行checkForComodification方法:

final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); }

这里会做迭代器内部修改次数检查,因为上面的remove(Object)方法把修改了modCount的值,所以才会报出并发修改异常。要避免这种情况的出现则在使用迭代器迭代时(显示或foreach的隐式)不要使用ArrayList的remove,改为用Iterator的remove即可。

public static void remove(ArrayList<String> list) { Iterator<String> it = list.iterator(); while (it.hasNext()) { String s = it.next(); if (s.equals("bb")) { it.remove(); } } }

2. 说一说ArrayList 的扩容机制吧

ArrayList扩容的本质就是计算出新的扩容数组的size后实例化,并将原有数组内容复制到新数组中去。

public boolean add(E e) { //扩容 ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true; } private void ensureCapacityInternal(int minCapacity) { ensureExplicitCapacity(calculateCapacity(elementData, minCapacity)); }

private static int calculateCapacity(Object[] elementData, int minCapacity) { //如果传入的是个空数组则最小容量取默认容量与minCapacity之间的最大值 if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { return Math.max(DEFAULT_CAPACITY, minCapacity); } return minCapacity; } private void ensureExplicitCapacity(int minCapacity) { modCount++; // 如果最小需要空间比elementData的内存空间要大,则需要扩容 // overflow-conscious code if (minCapacity - elementData.length > 0) grow(minCapacity); } private void grow(int minCapacity) { // 获取elementData数组的内存空间长度 int oldCapacity = elementData.length; // 扩容至原来的1.5倍 int newCapacity = oldCapacity + (oldCapacity >> 1); //校验容量是否够 if (newCapacity - minCapacity < 0) newCapacity = minCapacity; //若预设值大于默认的最大值,检查是否溢出 if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); // 调用Arrays.copyOf方法将elementData数组指向新的内存空间 //并将elementData的数据复制到新的内存空间 elementData = Arrays.copyOf(elementData, newCapacity); }

3. HashMap是怎么解决哈希冲突的

Hashmap解决hash冲突,使用的是链地址法,即数组+链表的形式来解决。put执行首先判断table[i]位置,如果为空就直接插入,不为空判断和当前值是否相等,相等就覆盖,如果不相等的话,判断是否是红黑树节点,如果不是,就从table[i]位置开始遍历链表,相等覆盖,不相等插入。

4. String 类的常用方法都有那些?

  • indexOf():返回指定字符的索引。
  • charAt():返回指定索引处的字符。
  • replace():字符串替换。
  • trim():去除字符串两端空白。
  • split():分割字符串,返回一个分割后的字符串数组。
  • getBytes():返回字符串的 byte 类型数组。
  • length():返回字符串长度。
  • toLowerCase():将字符串转成小写字母。
  • toUpperCase():将字符串转成大写字符。
  • substring():截取字符串。
  • equals():字符串比较。

5. 简述Java中的集合

  1. Collection下:List系(有序、元素允许重复)和Set系(无序、元素不重复) “ set根据equals和hashcode判断,一个对象要存储在Set中,必须重写equals和hashCode方法 ”
  2. Map下:HashMap线程不同步;TreeMap线程同步
  3. Collection系列和Map系列:Map是对Collection的补充,两个没什么关系

“ 后面的问题,大家可以先自己独立思考一下。 另外我把所有Java相关的面试题和答案都整理出来了,需要的私信,即可免费获取哦!

6. EnumSet是什么?

7. 创建String对象的不同方式有哪些?

8. 为何Map接口不继承Collection接口?

9. HashMap和Hashtable的区别

10. ArrayList和HashMap默认大小?

11. LinkedList的是单向链表还是双向?

12. 当一个集合被作为参数传递给一个函数时,如何才可以确保函数不能修改它?

13. 在Java中,HashMap是如何工作的?

14. TreeMap和TreeSet在排序时如何比较元素?Collections工具类中的sort()方法如何比较元素?

15. HashSet和TreeSet有什么区别?

16. String是不可变的有什么好处?

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

18. HashSet是如何保证不重复的

19. HashMap的实现原理

20. Iterater和ListIterator之间有什么区别?

21. 队列和栈是什么,列出它们的区别?

22. HashMap线程安全吗?

23. 写一段代码在遍历 ArrayList 时移除一个元素

24. 有没有有顺序的Map实现类,如果有,他们是怎么保证有序的

25. ArrayList,Vector,LinkedList的存储性能和特性

26. 什么是字符串池?

27. 哪些集合类提供对元素的随机访问?

28. hashCode()和equals()方法有何重要性?

29. 我们能否使用任何类作为Map的key?

30. # 总结

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

32. ArrayList和Vector有何异同点?

33. HashMap,HashTable,ConcurrentHash的共同点和区别

34. Set里的元素是不能重复的,那么用什么方法来区分重复与否呢? 是用==还是equals()?

35. Java中的同步集合与并发集合有什么区别

36. String str="i"与 String str=new String("i")一样吗?

37. 下面这条语句一共创建了多少个对象:String s="a"+"b"+"c"+"d"

38. 如果想用Object作为hashMap的Key?;

39. Java 中操作字符串都有哪些类?它们之间有什么区别?

40. 谈谈线程池阻塞队列吧~

41. Java集合框架是什么?说出一些集合框架的优点?

42. 与Java集合框架相关的有哪些最好的实践?

43. TreeMap底层?

44. ArrayList和LinkedList有何区别?

45. 我们如何从给定集合那里创建一个synchronized的集合?

46. Java中怎么打印数组?

47. 当一个集合被作为参数传递给一个函数时,如何才可以确保函数不能修改它?

48. 如何决定选用HashMap还是TreeMap?

49. HashMap总结

50. 说出ArrayList,LinkedList的存储性能和特性

51. Collections类是什么?

52. Comparator和Comparable的区别?

53. Iterator和ListIterator的区别是什么?

54. List、Map、Set三个接口,存取元素时,各有什么特点?

55. Comparable和Comparator接口有何区别?

56. Map接口提供了哪些不同的集合视图?

57. 哪些集合类是线程安全的?哪些不安全?

58. 通过迭代器fail-fast属性,你明白了什么?

59. HashMap和HashTable有何不同?

60. 为何Iterator接口没有具体的实现?

61. 如何实现集合排序?

62. 如何比较两个字符串?

63. 讲讲红黑树的特点?

64. 遍历一个List有哪些不同的方式?

65. 集合框架里实现的通用算法有哪些?

66. UnsupportedOperationException是什么?

67. 为何没有像Iterator.add()这样的方法,向集合中添加元素?

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

69. Collection与Collections的区别是什么?

70. LinkedHashMap的应用,底层,原理

71. ArrayList 和 HashMap 的默认大小是多数?

72. HashMap自动扩容

73. HashMap在JDK1.7和JDK1.8中有哪些不同?

74. 什么是String,它是什么数据类型?

75. Set里的元素是不能重复的,那么用什么方法来区分重复与否呢?是用==还是equals()?它们有何区别?

76. ArrayList和Vector的区别

77. 在迭代一个集合的时候,如何避免ConcurrentModificationException?

78. 如何判断两个String是否相等?

79. LinkedHashMap和PriorityQueue的区别

80. String s = new String("xyz");创建了几个StringObject?是否可以继承String类?

81. HashMap为什么不直接使用hashCode()处理后的哈希值直接作为table的下标?

82. Collections.sort和Arrays.sort的实现原理

83. 为何迭代器没有一个方法可以直接获取下一个元素,而不需要移动游标?

84. 如何打印数组内容

85. 大写的O是什么?举几个例子?

86. 为什么HashMap中String、Integer这样的包装类适合作为key?

87. 如何将String转换为byte array,反过来呢?

88. BlockingQueue是什么?

89. 阻塞队列的实现,ArrayBlockingQueue的底层实现?

90. 如何分割一个String?

91. Array和ArrayList有何区别?什么时候更适合用Array?

92. 如何让一个字符串变成小写或大写形式?

93. 说一下HashSet的实现原理?

94. 迭代器 Iterator 是什么?怎么用,有什么特点?

95. fail-fast与fail-safe有什么区别?

96. ArrayList和LinkedList区别?

97. String、StringBuffer和StringBuilder区别(类似上一题)

98. 怎么确保一个集合不能被修改?

99. Iterator是什么?

100. ArrayList和LinkedList的区别?

101. ArrayList集合加入1万条数据,应该怎么提高效率

102. 为什么要引入SpringBuffer、StringBuilder两种字符串处理类?

103. HashMap的扩容操作是怎么实现的?

104. 什么是Java优先级队列(Priority Queue)?

105. ArrayList和Array有什么区别?

106. ConcurrentHashMap和Hashtable的区别?

107. Comparable和Comparator接口是什么?

108. HashMap 的长度为什么是2的幂次方,以及其他常量定义的含义~

109. ConcurrenHashMap 原理?1.8 中为什么要用红黑树?

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

111. Enumeration和Iterator接口的区别?

112. 我们如何对一组对象进行排序?

113. WeakHashMap与HashMap的区别是什么?

114. 如何将String转换为char,反过来呢?

115. 并发集合类是什么?

116. poll()方法和remove()方法区别?

117. Java中的集合及其继承关系

118. 为何Collection不从Cloneable和Serializable接口继承?

119. HashMap的put方法的具体流程?

120. TreeMap的实现原理

121. 如何对Object的list排序

122. Array 和 ArrayList 有何区别?

需要上述最新面试资料的小伙伴们,关注后私信“需要”,即可免费获取哦!

版权声明:程序员胖胖胖虎阿 发表于 2022年9月5日 上午10:40。
转载请注明:2022Java面试题大全,附答案,最新整理 | 胖虎的工具箱-编程导航

相关文章

暂无评论

暂无评论...