Java中的容器讲解

本文深入解析Java中的数据结构,包括线性表、链表、集合、哈希表等,并对比了ArrayList与LinkedList、HashMap与Hashtable等类的区别。指导开发者如何根据应用场景选择合适的数据结构。

线性表,链表,集合,哈希表是常用的数据结构,在进行Java开发时,JDK已经为我们提供了一系列相应的类来实现基本的数据结构。这些类均在java.util包中。

Collection
├List
│-├LinkedList
│-├ArrayList
│-└Vector
│ └Stack
└Set

Map
├Hashtable
├HashMap
└WeakHashMap


主要分为两个分支:Collection和Map ,其中Map中存储的对象是以名值对的方式储存的,如:<name,value>

是字典的实现。

由Collection接口派生的两个接口是List和Set
其中,List的特点是:有顺序而可以重复Set的特点是:无顺序而不可重复
什么是重复?
不是说容器中有两个格子装了同一个对象,重复是指:a.equals(b) == true; 所以,当我们自定义对象作为容器的储存元素时,我们必须重写 java.lang.Object的equals方法,Object的默认equals只有当比较的参数是本身时才返回true,明显不是我们想要的,所以必须重写,而且,如果重写equals就必须重写hashCode()方法,因为,当我们的对象作为字典Map的键key时,我们的定位是同过 hashCode方法,这样来提高效率。注:两个对象equals若为TRUE,hashCode一定返回同样的int;但是,如果Equals返回 FALSE,hashCode不一定不同。


List接口

有重复、有序


List是有序的Collection,使用此接口能够精确的控制每个元素插入的位置。用户能够使用索引(元素在List中的位置,类似于数组下标)来访问List中的元素,这类似于Java的数组。

和下面要提到的Set不同,List允许有相同的元素。

除了具有Collection接口必备的iterator()方法外,List还提供一个listIterator()方法,返回一个 ListIterator接口,和标准的Iterator接口相比,ListIterator多了一些add()之类的方法,允许添加,删除,设定元素, 还能向前或向后遍历。

实现List接口的常用类有LinkedList,ArrayList,Vector和Stack。
ArrayList(数组表)- 有重复、有顺序。类似于Vector,都用于缩放数组维护集合。
区别:

1.同步性:Vector是线程安全的,也就是说是同步的,而ArrayList是线程序不安全的,不是同步的

2.数据增长:当需要增长时,Vector默认增长为原来一培,而ArrayList却是原来的一半

LinkedList(链表)-是双向链表,适合变更很多的List。

用在FIFO,用addList()加入元素 removeFirst()删除元素

用在FILO,用addFirst()/removeLast()

ListIterator提供双向遍历next() previous(),可删除、替换、增加元素


LinkedList类

LinkedList实现了List接口,允许null元素。此外LinkedList提供额外的get,remove,insert方法在 LinkedList的首部或尾部。这些操作使LinkedList可被用作堆栈(stack),队列(queue)或双向队列(deque)。

注意LinkedList没有同步方法。如果多个线程同时访问一个List,则必须自己实现访问同步。一种解决方法是在创建List时构造一个同步的List:
    List list = Collections.synchronizedList(new LinkedList(...));

ArrayList类
ArrayList实现了可变大小的数组。它允许所有元素,包括null。ArrayList没有同步。

size,isEmpty,get,set方法运行时间为常数。但是add方法开销为分摊的常数,添加n个元素需要O(n)的时间。其他的方法运行时间为线性。

每个ArrayList实例都有一个容量(Capacity),即用于存储元素的数组的大小。这个容量可随着不断添加新元素而自动增加,但是增长算法并 没有定义。当需要插入大量元素时,在插入前可以调用ensureCapacity方法来增加ArrayList的容量以提高插入效率。

和LinkedList一样,ArrayList也是非同步的(unsynchronized)。

一般情况下使用这两个就可以了,因为非同步,所以效率比较高。

Vector类
Vector非常类似ArrayList,但是Vector是同步的。由Vector创建的Iterator,虽然和ArrayList创建的 Iterator是同一接口,但是,因为Vector是同步的,当一个 Iterator被创建而且正在被使用,另一个线程改变了Vector的状态(例 如,添加或删除了一些元素),这时调用Iterator的方法时将抛出 ConcurrentModificationException,因此必须捕获该 异常。

Stack 类
Stack继承自Vector,实现一个后进先出的堆栈。Stack提供5个额外的方法使得Vector得以被当作堆栈使用。基本的push和pop方 法,还有 peek方法得到栈顶的元素,empty方法测试堆栈是否为空,search方法检测一个元素在堆栈中的位置。Stack刚创建后是空栈。

Set接口
Set的构造函数有一个约束条件,传入的Collection参数不能包含重复的元素。

Map接口
请注意,Map没有继承Collection接口,Map提供key到value的映射。一个Map中不能包含相同的key,每个key只能映射一个 value。Map接口提供3种集合的视图,Map的内容可以被当作一组key集合,一组value集合,或者一组key-value映射。

Map用于关键字/数值对,较高的存取性能。不允许重复的key,但允许重复的Value。

处理Map的三种集合

关键字集KeySet() 数值集value()   项目集enrySet()

四个具体版本

HashMap-散列表的通用映射表,无序,可在初始化时设定其大小,自动增长。

LinkedHashMap-扩展HashMap,对返回集合迭代时,维护插入顺序

WeakHashMap-基于弱引用散列表的映射表,如果不保持映射表外的关键字的引用,则内存回收程序会回收它

TreeMap-基于平衡树的映射表 



Hashtable类
Hashtable继承Map接口,实现一个key-value映射的哈希表。任何非空(non-null)的对象都可作为key或者value。
添加数据使用put(key, value),取出数据使用get(key),这两个基本操作的时间开销为常数。
Hashtable 通过initial capacity和load factor两个参数调整性能。通常缺省的load factor 0.75较好地实现了时间和空间的均衡。增大load factor可以节省空间但相应的查找时间将增大,这会影响像get和put这样的操作。
Hashtable是同步的。

HashMap类
HashMap和Hashtable类似,不同之处在于HashMap是非同步的,并且允许null,即null value和null key。,但是将HashMap视为Collection时(values()方法可返回 Collection),其迭代子操作时间开销和HashMap 的容量成比例。因此,如果迭代操作的性能相当重要的话,不要将HashMap的初始化容量设得过高,或者load factor过低。

WeakHashMap类
WeakHashMap是一种改进的HashMap,它对key实行“弱引用”,如果一个key不再被外部所引用,那么该key可以被GC回收。

一般情况下数据结构的选择:
多查少改选ArrayList
多改少查选LinkedList
如果大量数据进行检索选Map,


详细:
如果涉及到堆栈,队列等操作,应该考虑用List,对于需要快速插入,删除元素,应该使用LinkedList,如果需要快速随机访问元素,应该使用ArrayList。
如果程序在单线程环境中,或者访问仅仅在一个线程中进行,考虑非同步的类,其效率较高,如果多个线程可能同时操作一个类,应该使用同步的类。
要特别注意对哈希表的操作,作为key的对象要正确复写equals和hashCode方法。
尽量返回接口而非实际的类型,如返回List而非ArrayList,这样如果以后需要将ArrayList换成LinkedList时,客户端代码不用改变。这就是针对抽象编程。


同步性
Vector是同步的。这个类中的一些方法保证了Vector中的对象是线程安全的。而ArrayList则是异步的,因此ArrayList中的对象并不是线程安全的。因为同步的要求会影响执行的效率,所以如果你不需要线程安全的集合那么使用ArrayList是一个很好的选择,这样可以避免由于同步带来的不必要的性能开销。

数据增长

从内部实现机制来讲ArrayList和Vector都是使用数组(Array)来控制集合中的对象。当你向这两种类型中增加元素的时候,如果元素的数目超出了内部数组目前的长度它们都需要扩展内部数组的长度,Vector缺省情况下自动增长原来一倍的数组长度,ArrayList是原来的50%,所以最后你获得的这个集合所占的空间总是比你实际需要的要大。所以如果你要在集合中保存大量的数据那么使用Vector有一些优势,因为你可以通过设置集合的初始化大小来避免不必要的资源开销。

辅助类java.lang.Collections

这个类封装了一些List的算法,包括排序,逆向,随机排序等等。

重要需要实现的接口:

Comparable接口,当两个对象涉及比较操作时,使用这个接口的compareTo方法。

Iterator接口,涉及遍历时使用。

常见问题

1、Collection 和 Collections的区别。

Collections是个java.util下的类,它包含有各种有关java集合操作的静态方法。 

Collection是个java.util下的接口,它是各种java集合结构的父接口

2、List, Set, Map是否继承自Collection接口? List,Set是 Map不是

3、ArrayList和Vector的区别

(1).同步性:Vector是线程安全的,也就是说是同步的,而ArrayList是线程序不安全的,不是同步的

(2).数据增长:当需要增长时,Vector默认增长为原来一培,而ArrayList却是原来的一半

4、HashMap和Hashtable的区别

(1).历史原因:Hashtable是基于陈旧的Dictionary类的,HashMap是Java 1.2引进的Map接口的一个实现

(2).同步性:Hashtable是线程安全的,也就是说是同步的,而HashMap是线程序不安全的,不是同步的

(3).值:只有HashMap可以让你将空值作为一个表的条目的key或value



<think>好的,我现在需要帮助用户了解Java中的容器概念和用法,特别是数据结构方面的内容。首先,用户提到了“Java 容器详解”和数据结构,所以我要先整理Java容器的基础知识,包括分类、常见容器类及其数据结构。 根据用户提供的引用,引用[1]和[2]都提到了容器的分类和比较器的使用,引用[3]则涉及HashMap的数据结构。我需要结合这些信息,但用户的问题更偏向整体容器,而不仅仅是HashMap。因此,我应该从整体结构入手,分单例和双例集合,然后详细说明常用的容器类。 首先,Java容器分为Collection和Map两大类。Collection是单列集合,包括List、Set、Queue;Map是双列集合,存储键值对。需要明确每个接口的特点和实现类。 接下来,数据结构部分。比如ArrayList基于数组,LinkedList基于链表,HashSet和HashMap基于哈希表,TreeSet和TreeMap基于红黑树,LinkedHashMap和LinkedHashSet维护插入顺序。需要把这些数据结构容器类对应起来,说明它们的优缺点和适用场景。 然后,用户可能关心如何选择容器,所以需要给出一些使用建议,比如需要快速访问用ArrayList,频繁插入删除用LinkedList,需要唯一性用HashSet,需要排序用TreeSet等。 另外,引用中提到的比较器Comparator的使用,应该在讲解TreeSet或排序时提及,比如如何通过比较器自定义排序规则,这样用户能了解容器的扩展用法。 需要注意用户可能对数据结构的具体实现感兴趣,比如HashMap在JDK8之后使用数组+链表+红黑树的结构,当链表长度超过8时转成红黑树,小于6时转回来,这点在引用[3]中有提到,可以适当强调。 最后,生成相关问题时要围绕容器的分类、数据结构比较、选择策略、线程安全等,帮助用户深入思考。 需要确保回答结构清晰,分点说明,使用中文,数学公式用$...$,独立公式用$$...$$,但可能在这个问题中用到的数学公式不多,可能涉及复杂度分析,比如ArrayList的访问是$O(1)$,LinkedList插入是$O(1)$等。 检查引用是否正确应用,比如在讲解TreeSet比较器时引用[1],在Collections.sort时引用[2],在HashMap结构时引用[3]。 总结回答结构: 1. 容器分类:单列(List、Set、Queue)和双列(Map) 2. 核心接口和实现类 3. 数据结构分析:每个容器的底层结构 4. 比较器的作用(引用[1][2]) 5. HashMap的数据结构优化(引用[3]) 6. 使用建议 7. 相关问题 需要确保内容准确,比如HashSet确实基于HashMap实现,TreeSet基于TreeMap,LinkedHashSet维护链表等。避免错误,比如ArrayList的扩容机制是1.5倍,LinkedList是双向链表等。 现在组织语言,用清晰的中文分点说明,并自然地插入引用标注。</think>### Java容器概念与数据结构详解 #### 一、Java容器分类 Java容器分为**单列集合(Collection)**和**双列集合(Map)**两大类: 1. **单列集合**:存储单个元素 - **List**:有序、可重复(如$ArrayList$、$LinkedList$) - **Set**:无序、不可重复(如$HashSet$、$TreeSet$) - **Queue**:队列结构(如$PriorityQueue$) 2. **双列集合**:存储键值对(Key-Value) - **Map**:键唯一,值可重复(如$HashMap$、$TreeMap$)[^1] #### 二、核心容器类与数据结构 | 容器类 | 数据结构 | 特点 | |-----------------|-------------------------|----------------------------------------------------------------------| | **ArrayList** | 动态数组 | 支持$O(1)$随机访问,扩容时增长50% | | **LinkedList** | 双向链表 | 插入/删除$O(1)$,但随机访问$O(n)$ | | **HashSet** | 哈希表 + 链表 | 基于$HashMap$实现,通过哈希函数计算存储位置 | | **TreeSet** | 红黑树 | 元素按自然顺序或自定义规则排序(需实现$Comparable$或提供$Comparator$)[^1] | | **HashMap** | 数组+链表+红黑树(JDK8+)| 链表长度≥8时转为红黑树,<6时转回链表,优化查询性能[^3] | | **LinkedHashMap**| 哈希表 + 双向链表 | 维护插入顺序或访问顺序 | #### 三、数据结构关键点 1. **动态数组(ArrayList)** - 初始容量10,扩容公式:$$新容量 = 旧容量 \times 1.5$$ - 适用场景:频繁随机访问,尾部插入/删除。 2. **红黑树(TreeMap/TreeSet)** - 自平衡二叉搜索树,保证插入、删除、查找的时间复杂度为$O(\log n)$。 - 排序规则可通过比较器定义(示例代码): ```java // 按年龄升序,年龄相同按姓名排序 public class StudentComparator implements Comparator<Student> { @Override public int compare(Student o1, Student o2) { if (o1.getAge() > o2.getAge()) return 1; else if (o1.getAge() == o2.getAge()) return o1.getName().compareTo(o2.getName()); else return -1; } } ``` 使用时传入`TreeSet`构造函数[^1]。 3. **哈希冲突处理(HashMap)** - 哈希函数:`(key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16)` - 链表转红黑树阈值:8(优化极端哈希冲突下的性能)[^3]。 #### 四、容器选择建议 1. 需要**快速访问**且少插入/删除 → $ArrayList$ 2. 需要**频繁插入/删除** → $LinkedList$ 3. 需要**去重** → $HashSet$ 4. 需要**排序** → $TreeSet$(自定义比较器见[^1][^2]) 5. 需要**键值对存储** → $HashMap$(高频读写)、$LinkedHashMap$(维护顺序) #### 五、线程安全与扩展 - **非线程安全容器**:$ArrayList$、$HashMap$(性能高) - **线程安全替代方案**: - 使用`Collections.synchronizedList()`包装 - 改用$ConcurrentHashMap$(分段锁或CAS优化)
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值