如果一个Java对象可以在内部持有若干其他Java对象,并对外提供访问接口,我们把这种Java对象称为集合。
Java集合框架
Collection
Java标准库自带的java.util
包提供了集合类:Collection
,它是所有其他集合类的根接口。在Collection
的基础上,Java的java.util
包主要提供了以下三种类型的集合:
List
:一种有序列表的集合,例如,按索引排列的Student
的List
;Set
:一种保证没有重复元素的集合,例如,所有无重复名称的Student
的Set
;Map
:一种通过键值(key-value)查找的映射表集合,例如,根据Student
的name
查找对应Student
的Map
。
Java访问集合总是通过统一的方式——迭代器(Iterator)来实现,好处在于无需知道集合内部元素是按什么方式存储的。
遗留类、遗留接口不应该继续使用:
Hashtable
:一种线程安全的Map
实现;Vector
:一种线程安全的List
实现;Stack
:基于Vector
实现的LIFO
的栈。Enumeration<E>
:已被Iterator<E>
取代。
List
List是一种有序链表,有序结构,类似数组。
需要增删元素的有序列表,使用最多的是ArrayList
,ArrayList
在内部使用了数组来存储所有元素。
ArrayList
把添加和删除的操作封装起来,操作List
类似于操作数组,却不用关心内部元素如何移动。
考察List<E>
接口,可以看到几个主要的接口方法:
- 在末尾添加一个元素:
void add(E e)
- 在指定索引添加一个元素:
void add(int index, E e)
- 删除指定索引的元素:
int remove(int index)
- 删除某个元素:
int remove(Object e)
- 获取指定索引的元素:
E get(int index)
- 获取链表大小(包含元素的个数):
int size()
LinkedList
通过“链表”也实现了List接口。
比较ArrayList
和LinkedList
:
ArrayList | LinkedList | |
---|---|---|
访问指定元素 | 速度很快 | 需要从头开始查找元素 |
添加元素到末尾 | 速度很快 | 速度很快 |
在指定位置添加/删除 | 需要移动元素 | 不需要移动元素 |
内存占用 | 少 | 较大 |
创建List
1 | import java.util.ArrayList; |
根据给定元素快速创建List
:
1 | List<Integer> list = List.of(1, 2, 5); |
List.of()
方法不接受null
值,如果传入null
,会抛出NullPointerException
异常。
遍历List
和数组类型,我们要遍历一个List,完全可以用for循环根据索引配合get(int)
方法遍历:
1 | import java.util.List; |
List
内部并不是通过==
判断两个元素是否相等,而是使用equals()
方法判断两个元素是否相等。
equals()
方法要求我们必须满足以下条件:
自反性(Reflexive):对于非
null
的x
来说,x.equals(x)
必须返回true
;对称性(Symmetric):对于非
null
的x
和y
来说,如果x.equals(y)
为true
,则y.equals(x)
也必须为true
;传递性(Transitive):对于非
null
的x
、y
和z
来说,如果x.equals(y)
为true
,y.equals(z)
也为true
,那么x.equals(z)
也必须为true
;一致性(Consistent):对于非
null
的x
和y
来说,只要x
和y
状态不变,则x.equals(y)
总是一致地返回true
或者false
;对
null
的比较:即x.equals(null)
永远返回false
。
一般遍历数组都是采用for循环,推荐用迭代器Iterator
来访问List
,采用迭代器遍历集合框架,它是一个对象,实现了Iterator 接口或ListIterator接口。
迭代器,使你能够通过循环来得到或删除集合的元素。ListIterator 继承了Iterator,以允许双向遍历列表和修改元素。
遍历 ArrayList
1 | import java.util.*; |
第三种方法是采用迭代器的方法,该方法可以不用担心在遍历的过程中超出集合的长度。
遍历Map
1 | import java.util.*; |
Set
Set<Map.Entry<K,V>> entrySet() //返回映射所包含的映射关系的Set集合(一个关系就是一个键-值对),就是把(key-value)作为一个整体一对一对地存放到Set集合当中的。正确使用Map
必须保证:
- 作为
key
的对象必须正确覆写equals()
方法,相等的两个key
实例调用equals()
必须返回true
; - 作为
key
的对象还必须正确覆写hashCode()
方法,且hashCode()
方法要严格遵循以下规范:
- 如果两个对象相等,则两个对象的
hashCode()
必须相等; - 如果两个对象不相等,则两个对象的
hashCode()
尽量不要相等。
EnumMap
如果作为key的对象是enum
类型,那么,还可以使用Java集合库提供的一种EnumMap
,它在内部以一个非常紧凑的数组存储value,并且根据enum
类型的key直接定位到内部数组的索引,并不需要计算hashCode()
,不但效率最高,而且没有额外的空间浪费。
如果Map
的key是enum
类型,推荐使用EnumMap
,既保证速度,也不浪费空间。
使用EnumMap
的时候,根据面向抽象编程的原则,应持有Map
接口。
TreeMap
一种Map
,它在内部会对Key进行排序,这种Map
就是SortedMap
。注意到SortedMap
是接口,它的实现类是TreeMap
。
1 | ┌───┐ |
SortedMap
保证遍历时以Key的顺序来进行排序。例如,放入的Key是"apple"
、"pear"
、"orange"
,遍历的顺序一定是"apple"
、"orange"
、"pear"
,因为String
默认按字母排序。
发布时间: 2019-08-18
最后更新: 2019-08-31
本文链接: https://juoyo.github.io/posts/c9981ec.html
版权声明: 本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。转载请注明出处!