02 - Java 容器

本章节深入探讨 Java 集合框架(Containers),这是 Java 编程中处理数据结构的核心。涵盖了 Collection 和 Map 体系、HashMap 的底层原理、ArrayList 与 LinkedList 的对比、线程安全的集合以及迭代器的使用。掌握这些内容对于优化程序性能和处理复杂数据至关重要。
<h3>1. java 容器都有哪些?</h3>
<p>Java 容器主要分为两大类:</p>
<ul>
<li><strong>Collection</strong>:存储对象的集合。</li>
<li><strong>List</strong>:有序,可重复(ArrayList, LinkedList, Vector)。</li>
<li><strong>Set</strong>:无序,不可重复(HashSet, TreeSet, LinkedHashSet)。</li>
<li><strong>Queue</strong>:队列(PriorityQueue, LinkedList, ArrayDeque)。</li>
<li><strong>Map</strong>:存储键值对(Key-Value)。</li>
<li>HashMap, TreeMap, Hashtable, LinkedHashMap, ConcurrentHashMap。</li>
</ul>
<h3>2. Collection 和 Collections 有什么区别?</h3>
<ul>
<li><strong>Collection</strong>:是一个接口,是 List, Set, Queue 的父接口。</li>
<li><strong>Collections</strong>:是一个工具类,包含了很多静态方法,用于操作集合(如排序 <code>sort</code>,反转 <code>reverse</code>,查找 <code>binarySearch</code>,线程安全化 <code>synchronizedList</code> 等)。</li>
</ul>
<h3>3. List、Set、Map 之间的区别是什么?</h3>
<table border="1" cellpadding="5" cellspacing="0">
<thead>
<tr>
<th>特性</th>
<th>List</th>
<th>Set</th>
<th>Map</th>
</tr>
</thead>
<tbody>
<tr>
<td>有序性</td>
<td>有序</td>
<td>无序(TreeSet 有序)</td>
<td>无序(TreeMap 有序)</td>
</tr>
<tr>
<td>重复性</td>
<td>可重复</td>
<td>不可重复</td>
<td>Key 不可重复,Value 可重复</td>
</tr>
<tr>
<td>存储结构</td>
<td>线性表</td>
<td>哈希表/树</td>
<td>哈希表/树</td>
</tr>
<tr>
<td>继承接口</td>
<td>Collection</td>
<td>Collection</td>
<td>无(独立接口)</td>
</tr>
</tbody>
</table>
<h3>4. HashMap 和 Hashtable 有什么区别?</h3>
<ul>
<li><strong>线程安全</strong>:Hashtable 是线程安全的(方法有 synchronized),HashMap 是非线程安全的。</li>
<li><strong>Null 值</strong>:HashMap 允许 Key 和 Value 为 null(Key 只能有一个 null),Hashtable 不允许。</li>
<li><strong>效率</strong>:HashMap 效率高于 Hashtable。</li>
<li><strong>继承</strong>:HashMap 继承 AbstractMap,Hashtable 继承 Dictionary(已过时)。</li>
</ul>
<h3>5. 如何决定使用 HashMap 还是 TreeMap?</h3>
<ul>
<li>如果需要<strong>快速插入、删除和查找</strong>(O(1)),使用 <strong>HashMap</strong>。</li>
<li>如果需要<strong>对 Key 进行排序</strong>(O(log n)),使用 <strong>TreeMap</strong>。</li>
</ul>
<h3>6. 说一下 HashMap 的实现原理?</h3>
<ul>
<li><strong>底层结构</strong>:</li>
<li>JDK 1.7:数组 + 链表。</li>
<li>JDK 1.8:数组 + 链表 + 红黑树。</li>
<li><strong>Put 过程</strong>:</li>
</ul>
<ol>
<li>计算 Key 的 hash 值,定位到数组索引。</li>
<li>如果该位置为空,直接插入。</li>
<li>如果该位置有数据(哈希冲突),使用链表或红黑树解决。</li>
<li>JDK 1.8 中,当链表长度超过 8 且数组长度超过 64 时,链表转为红黑树。</li>
</ol>
<ul>
<li><strong>扩容</strong>:当元素个数超过 <code>capacity <em> loadFactor</em></code><em>(默认 16 </em> 0.75 = 12)时,数组扩容为原来的 2 倍,并重新计算 Hash 分布。</li>
</ul>
<h3>7. 说一下 HashSet 的实现原理?</h3>
<p>HashSet 底层是基于 <strong>HashMap</strong> 实现的。</p>
<p>HashSet 的值作为 HashMap 的 Key 存储,Value 是一个固定的 Object 对象(PRESENT)。因此 HashSet 具有无序、不可重复的特性。</p>
<h3>8. ArrayList 和 LinkedList 的区别是什么?</h3>
<ul>
<li><strong>底层数据结构</strong>:ArrayList 是动态数组;LinkedList 是双向链表。</li>
<li><strong>随机访问</strong>:ArrayList 支持 O(1) 随机访问;LinkedList 需要 O(n) 遍历。</li>
<li><strong>插入删除</strong>:</li>
<li>ArrayList:尾部插入 O(1),中间插入/删除需要移动元素,O(n)。</li>
<li>LinkedList:头尾插入/删除 O(1),中间插入/删除需要先遍历找到位置 O(n),但不需要移动元素。</li>
<li><strong>空间占用</strong>:LinkedList 每个节点需要存储前后指针,空间占用较大。</li>
</ul>
<h3>9. 如何实现数组和 List 之间的转换?</h3>
<ul>
<li><strong>数组转 List</strong>:<code>Arrays.asList(array)</code>。注意:返回的 List 是 Arrays 的内部类,固定长度,不支持 add/remove。</li>
<li><strong>List 转数组</strong>:<code>list.toArray()</code>。</li>
</ul>
<h3>10. ArrayList 和 Vector 的区别是什么?</h3>
<ul>
<li><strong>线程安全</strong>:Vector 是线程安全的(synchronized),ArrayList 不是。</li>
<li><strong>扩容</strong>:Vector 默认扩容 2 倍,ArrayList 默认扩容 1.5 倍。</li>
<li><strong>性能</strong>:ArrayList 性能优于 Vector。</li>
</ul>
<h3>11. Array 和 ArrayList 有何区别?</h3>
<ul>
<li><strong>类型</strong>:Array 可以包含基本类型和对象类型;ArrayList 只能包含对象类型(基本类型需装箱)。</li>
<li><strong>大小</strong>:Array 大小固定;ArrayList 大小动态变化。</li>
<li><strong>功能</strong>:ArrayList 提供了更多的方法(addAll, removeAll, iterator 等)。</li>
</ul>
<h3>12. 在 Queue 中 poll()和 remove()有什么区别?</h3>
<ul>
<li><strong>相同点</strong>:都是返回并删除队头元素。</li>
<li><strong>不同点</strong>:当队列为空时,<code>poll()</code> 返回 null,而 <code>remove()</code> 抛出 <code>NoSuchElementException</code> 异常。</li>
</ul>
<h3>13. 哪些集合类是线程安全的?</h3>
<ul>
<li><strong>Vector</strong></li>
<li><strong>Hashtable</strong></li>
<li><strong>Stack</strong></li>
<li><strong>java.util.concurrent 包下的集合</strong>:ConcurrentHashMap, CopyOnWriteArrayList, BlockingQueue 等。</li>
</ul>
<h3>14. 迭代器 Iterator 是什么?</h3>
<p>Iterator 是一个接口,用于遍历集合(Collection)中的元素。它提供了一种统一的遍历方式,而不需要了解集合底层的实现细节。</p>
<h3>15. Iterator 怎么使用?有什么特点?</h3>
<ul>
<li><strong>使用</strong>:</li>
</ul>
<pre>
<code> Iterator it = list.iterator();
while(it.hasNext()) {
String obj = it.next();
// it.remove(); // 安全删除
}</code></pre>
<ul>
<li><strong>特点</strong>:只能单向遍历,支持在遍历过程中安全地删除元素(使用 <code>it.remove()</code>),如果使用集合自己的 <code>remove()</code> 方法会抛出 <code>ConcurrentModificationException</code>。</li>
</ul>
<h3>16. Iterator 和 ListIterator 有什么区别?</h3>
<ul>
<li><strong>范围</strong>:Iterator 可以遍历 Set and List;ListIterator 只能遍历 List。</li>
<li><strong>方向</strong>:Iterator 只能单向(后);ListIterator 可以双向(前/后)。</li>
<li><strong>功能</strong>:ListIterator 可以添加元素(add)、修改元素(set)、获取索引(nextIndex/previousIndex)。</li>
</ul>
<h3>17. 怎么确保一个集合不能被修改?</h3>
<p>可以使用 <code>Collections.unmodifiableCollection(list)</code>(或 unmodifiableList, unmodifiableSet, unmodifiableMap)。</p>
<pre>
<code>List list = new ArrayList<>();
list.add("x");
List unmodifiableList = Collections.unmodifiableList(list);
// unmodifiableList.add("y"); // 抛出 UnsupportedOperationException</code></pre>
评论 (0)
加载评论中…