集合
记录单个数据,使用声明变量记录;
记录多个相同类型数据,使用数组记录;
而需要记录多个类型不同的对象时,使用集合;
集合与数组差异点:
-
数组长度固定
集合大小可以变 -
数组可以存储基本数据类型和引用数据类型
集合中只能存储引用数据类型(存储的为对象的内存地址) -
数组中只能存储同一种类型成员
集合中可以存储不同类型数据(一般情况下也只存储同一种类型的数据)
集合可以分为1、集合(Collection),储存元素集合;2、图(Map),存储键/值对映射。
注意: Collection集合操作元素的基本单位是单个元素,Map集合操作元素的基本单位是单对元素。
Collection接口又有3种类型,List,Set 和 Queue,在下面是一些抽象类,最后是具体实现类,常用的有ArrayList、LinkedList、HashSet、LinkedHashSet、HashMap、LinkedHashMap等。
List集合
List是用于有序存储可重复元素的集合。List接口继承Collection接口,声明有序存储对象(可重复)功能的公共接口。(只能存储引用数据类型)
List集合常用方法
方法 | 说明 |
---|---|
add(Object element) | 向列表末尾追加一个对象 |
void add(int index,Object element) | 在指定位置index上插入元素element |
boolean addAll(int index,Collection c) | 在指定位置index上插入集合c中的所有元素,如果List对象发生变化则返回true |
Object get(int index) | 返回指定位置index上的元素 |
Object remove(int index) | 删除指定位置index上的元素 |
Object set(int index,Object element) | 用元素element取代位置index上的元素,并且返回旧元素的取值 |
public int indexOf(Object obj) | 从列表的头部开始向后搜索元素obj,返回第一个出现元素obj的位置,若没有obj则返回-1 |
public int lastIndexOf(Object obj) | 从列表的尾部开始向前搜索元素obj,返回第一个出现元素obj的位置,若没有obj则返回-1 |
void clear() | 清空集合 |
boolean contains(Object o) | 判断元素在集合中是否存在,存在则返回true(底层调用equles) |
boolean isEmpty() | 判断集合是否为空,空则返回true |
int size() | 返回集合中元素个数 |
List集合的实现类有ArrayList 和 LinkedList:
LinkedList和ArrayList方法一样,只是底层实现不一样。ArrayList底层为数组存储,LinkedList是以双向链表存储。LinkedList集合没有初始化容量。最初这个链表中没有任何元素。first和last引用都是null。最大区别就是LinkedList更加灵活,并且部分方法的效率比ArrayList对应方法效率要高很多。频繁操作,建议使用LinkedList;对于数组变动不大,主要用于查询时,建议使用ArrayList。
扩容机制是在添加时才会自动扩容,扩容为原来的1.5倍,同时将原有数组中的数据复制到新的数组中。
-
链表的优点:
由于链表上的元素在空间存储上内存地址不连续。
所以随机增删元素的时候不会有大量元素位移,因此随机增删效率较高。 -
链表的缺点:
不能通过数学表达式计算被查找元素的内存地址,每一次查找都是从头
节点开始遍历,直到找到为止。所以LinkedList集合检索/查找的效率
较低。
Set集合
Set集合按照无序、不允许重复的方式存放对象。Set集合是无序的,没有下标,所以没有get方法。
存储特点:无需存储,且不可以存储相同的元素(排重),不能通过下标访问。
Set<T>集合实现类:基于散列结构(哈希表)的HashSet类和基于查找树结构的TreeSet类。
HashSet的底层结构
HashSet基于一种著名的、可以实现快速查找的散列表(Hash table)结构。
散列表也称哈希表,它采用按照对象的取值计算对象存储地址的策略,实现对象的“定位”存放,相应也提高了查找效率。
HashSet扩容
底层也是数组,初始容量为16,当如果使用率超过0.75,(16*0.75=12)就会扩大容量为原来的2倍。(16扩容为32,依次为64,128…等)
TressSet是基于查找树结构(回忆二叉树),具有排序功能的Set集合
HashSet类和TreeSet类对比:
- TreeSet是二叉树实现的,TreeSet中的数据是自动排好序的,不允许放入null值
- HashSet是哈希表实现的,HashSet中的数据是无序的,可以放入null,但只能放入一个null
- 两者中的值都不能重复,就如数据库中的唯一约束
- HashSet要求放入的对象必须实现hashCode()方法,放入的对象是以哈希码作为标识的
Map集合及实现类
Map集合与前面两种集合最大的区别就是:Map集合的一个元素是由两个数据组成的,即键值对;List集合和Set集合中的一个元素是由单个元素组成的。
Map集合特点:
- 存储的数据都是以键值对的形式存在的,即key:value形式
- Map中不能包含重复的键(一重复就覆盖),值可以重复,每个键只能对应一个值
方法 | 说明 |
---|---|
V put(K key,V value) | 若集合存在key键,则修改key键对应的值value;若没有,则添加元素 |
void clear() | 移除所有的键值对元素 |
V remove(Object key) | 移除键对应的元素,并把值返回 |
boolean containsKey(Object key) | 判断集合是否包含指定的键 |
boolean containsValue(Object value) | 判断集合是否包含指定的值 |
boolean isEmpty() | 判断集合是否为空 |
Set<.Map.Entry<K,V>>entrySet() | 遍历 |
V get(Object key) | 根据键获取值 |
Set < K > keySet() | 获取集合中所有键的集合 |
Collection< V >value | 获取集合中所有值的集合 |
int size() | 返回集合中的键值对的对数 |
Map集合的常见实现类为HashMap、TreeMap
HashMap特点:
-
根据哈希码值存储数据,表现为无序,不可重复。
-
放在HashMap集合key部分的元素其实就是放到HashSet集合中了。
所以HashSet集合中的元素也需要同时重写hashCode()+equals()方法。 -
HashMap集合的默认初始化容量是16,当HashMap集合底层数组的容量达到75%的时候,数组以二叉树开始扩容。
注意:HashMap集合初始化容量必须是2的倍数,这是因为为了达到散列均匀,为了提高HashMap集合的存取效率
TreeMap类特点:
- 所有元素的键都是有序的,基于红黑树(二叉树)数据结构实现的
- 添加元素时,元素的键具备自然顺序,那么就按自然顺序进行排序存储
- 添加元素时,元素的键没有自然顺序,那么键的所属类必须要实现Comparable接口,把键的比较规则定义在CompareTo()方法里
HashMap类与TreeMap类对比:
- HashMap通过hashCode()方法对其内容进行快速查找,而TreeMap是基于红黑树的一种访问的Map,所有的元素都保持这某种固定顺序。如果你需要得到一个有序的结果就应该使用TreeMap(HashMap中的元素排列顺序是不固定的)
- 两者的存取的时间复杂度都是O(log(n))
- 两者都是非线程安全的
- HashMap使用于Map中插入、删除和定位元素,TreeMap使用于按自然顺序或自定义顺序遍历键