集合与数组的区别
1、数组的长度是固定的,集合的长度是可变的;
2、数组用来存放基本类的数据,集合用来存放对象的引用
常用集合分类
- Collection(接口) ------存储一个元素集合
- List(接口)
- ArrayList(接口实现类)
- LinkedList(接口实现类)
- vector (接口实现类)
- Stack (vector接口的实现类)
- set (接口)
- EnumSet(接口实现类)
- TreeSet(接口实现类)
- HashSet(接口实现类)
- LinkedHashSet
- queue
- List(接口)
- Map(独立接口)------存储键/值对映射
- Hashtable(接口实现类)
- HashMap(接口实现类)
- TreeMap(接口实现类)
Collection接口
描述
Collection 是最基本的集合接口,java SDK不提供直接实现Collection的类,只提供继承于Collection子接口(List、set)的类
实现Collection接口的类
实现Collection接口的类都必须提供两个标准的构造函数
1、无参数的构造函数用于创建一个空的Collection;
2、带有Collection参数的有参构造函数(用于创建一个新的Collection)
Collection接口的常用方法
方法名 | 作用 |
---|---|
add() | 返回boolean 将指定的对象添加到该集合中 |
remove() | 返回boolean 将指定的对象从该集合中移除 |
isEmpty() | 返回 Boolean 用于判断当前集合是否为空 |
iterator() | 返回在此Collection 的元素上进行迭代的迭代器,用于遍历集合中的对象 例如Iterator it=list.iterator(); 创建迭代器 |
size() | 返回int 获取该集合中元素的个数 |
List集合
List集合包括List接口以及List接口的实现类,List是有序的,它用某种特定的插入顺序来维护元素顺
序,List集合中的元素允许重复,能够使用元素的整数索引(元素在List中的位置,类似于数组下标)来访问List中的元素
List接口定义的主要方法
方法名 | 功能 |
---|---|
get(int index) | 获取指定索引位置的元素 |
set (int index,Object o) | 修改集合中索引位置的对象为指定的对象 |
List接口的实现类
ArrayList
1、实现List的动态数组(大小是可以变化的),
2、底层使用数组(采用数组方式存储数据,实现了可变的数组 Object[] elementData)
3、允许保存所有元素包括null
4、并且可以根据索引位置对集合进行快速的随机访问
- ArrayList 实现不是同步的,线程不安全
- 向指定的索引位置插入对象后删除对象的速度比较慢
三种构造方法
1、无参构造函数 ArrayList()—当进行第一次add的时候,将会变成默认的长度:10.
2、带int类型的构造函数 ArrayList(int initialCapacity)
如果传入参数,则代表指定ArrayList的初始数组长度,传入参数如果是大于等于0,则使用用户的参数初始化,如果用户传入的参数小于0,则抛出异常
3、包含指定的Collection元素的构造函数 ArrayList(Collection c)
判断当前数组长度是否为0,为 0 则默认数组(EMPTY_ELEMENTDATA);否则进行数据拷贝。
常用方法
方法名 | 功能 |
---|---|
add(Object o) | 将指定的元素添加到此列表的末尾 (Boolean) |
add(int index,Object element) | 将指定的元素插入指定的位置 (Boolean) |
addAll(Collection<? extends E> c) | 将该Collection中的所有元素,按照collection迭代器返回的顺序,添加到该列表的尾部(Boolean) |
addAll(int index, Collection<? extends E> c) | 在列表中指定位置加入指定集合 |
set(int index, E element) | 用指定的元素代替列表中指定位置的元素 |
remove(int index) | 删除指定位置上的元素 |
clear() | 删除列表中所有的元素 |
remove(Object o) | 如果该元素存在于列表中,移除第一次出现的指定元素 |
removeRange(int fromIndex, int toIndex) | 移除fromIndex<=?<toIndex中的所有元素 |
LinkedList
1、采用双向链表方式存储数据
2、允许null元素
3、便于向集合中插入和删除对象
4、随机访问集合中的对象,效率较低
- LinkedList实现不是同步的,如果多个线程同时访问一个List,则必须自己实现访问同步。一种解决方法是在创建List时构造一个同步的List
List list = Collections.synchronizedList(new LinkedList(...));
定义
public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, java.io.Serializable
- LinkedList 是一个继承于AbstractSequentialList的双向链表。
- LinkedList 可以被当作堆栈、队列或双端队列进行操作。
- LinkedList 实现 List 接口,所以能对它进行队列操作。
- LinkedList 实现 Deque 接口,能将LinkedList当作双端队列使用。
- LinkedList 实现了Cloneable接口,即覆盖了函数clone(),能克隆。
- LinkedList 实现java.io.Serializable接口,所以LinkedList支持序列化,能通过序列化去传输。
两种构造方法
1、无参构造函数 LinkedList() —仅仅构造一个空的列表,没有任何元素。size = 0。first 和 last 都为 null
2、包含指定的Collection元素的构造函数 LinkedList(Collection<? extends E> c)
----该构造方法首先会调用空的构造方法,然后通过 addAll() 的方式把 Collection 中的所有元素添加进去。
LinkedList 提供了以下三个成员变量。size,first,last。
transient int size = 0;
transient Node<E> first;
transient Node<E> last;
- size 为 LinkedList 的大小,first 和 last 分别为链表的头结点和尾节点。Node 为节点对象
- Node 是 LInkedList 的内部类,定义了存储的数据元素,前一个节点和后一个节点,典型的双链表结构
常用方法
方法名 | 功能 |
---|---|
add(E e) | 添加元素到链表末尾 |
add(int index, E element) | 在链表的指定位置添加指定的元素 |
addAll(Collection<? extends E> c) | 将该Collection中的所有元素,按照collection迭代器返回的顺序,添加到该链表的结尾 |
remove(int index) | 移除指定位置的元素 |
remove(Object o) | 从此列表中移除首次出现的指定元素(如果存在) |
get(int index) | 返回此列表中指定位置处的元素(首先获取节点,然后返回节点的数据即可) |
indexOf(Object o) | 返回此链表首次出现 |
Vector
1、底层数据结构是数组
2、Vector 的大小是可以增加或者减小的
3、查询快,增删慢
- Vector是同步的 线程安全
- 当一个Iterator被创建而且正在被使用,另一个线程改变了Vector的状态(例如,添加或删除了一些元素),这时调用Iterator的方法时将抛出ConcurrentModificationException,因此必须捕获该异常
四种构造方法
1、默认构造函数 Vector()
2、 使用指定的初始容量和等于零的容量增量构造一个空向量 Vector(int capacity)—capacity是Vector的默认容量大小。当由于增加数据导致容量增加时,每次容量会增加一倍
3、 使用指定的初始容量和容量增量构造一个空的向量 Vector(int capacity, int capacityIncrement)----capacity是Vector的默认容量大小,capacityIncrement是每次Vector容量增加时的增量值。
4、创建一个包含collection的构造函数 Vector(Collection<? extends E> collection)
- Vector实际上是通过一个数组去保存数据的。当我们构造Vector时;若使用默认构造函数,则Vector的默认容量大小是10。
- capacityIncrement 增量值 (向量的大小大于其容量时,容量自动增加的量),若指定且>0,则每当Vector容量增加,增加的大小都是capacityIncrement ;否则,将容量大小增加一倍。
四种遍历方式
1、迭代器遍历,iterator遍历
Iterator<String> it = vec.iterator();
while(it.hasNext()) {
System.out.println(it.next());
}
2、随机访问
Integer value = null;
int size = vec.size();
for (int i=0; i<size; i++) {
value = (Integer)vec.get(i);
}
3、for循环
Integer value = null;
for (Integer integ:vec) {
value = integ;
}
4、Enumeration遍历
Integer value = null;
Enumeration enu = vec.elements();
while (enu.hasMoreElements()) {
value = (Integer)enu.nextElement();
}
- 遍历Vector,使用索引的随机访问方式最快,使用迭代器最慢。
Stack
Stack继承自Vector,实现一个后进先出的堆栈
只有一个构造方法
stack()
5个实现方法
方法名 | 功能 |
---|---|
empty() | 判断stack是否为空,返回值为boolean类型 |
peek() | 返回stack栈顶的元素,查看堆栈顶部的对象,如果栈为空,则报错栈为空 |
pop() | 取出栈顶的元素,并且返回该元素 |
push() | 将当前元素压入栈中,int型,string型,char型均可 |
search(Object o) | 查找“元素o”在栈中的位置:由栈底向栈顶方向数 ,寻找目标第一个出现的位置距离栈顶的距离,不存在的话返回值为-1 |
List总结
ArrayList:数组结构,线程不安全,查询速度快,增删速度慢(需要快速访问时)
LinkedList:链表结构,线程安全,查询速度慢,增删速度快(需要快速插入、删除元素时)
vector:数组结构,线程安全(多线程环境)
Set集合
set集合中的对象不按特定的方式排序,只是简单的把对象加入集合中,并且set集合中不能包含重复对象。有且只能有一个null
HashSet
1、HashSet采用哈希算法,底层用数组存储数据(无序,唯一) -----唯一性:靠所存储元素类型是否重写hashCode()和equals()方法来保证的,如果没有重写这两个方法,则无法保证元素的唯一性
2、线程不安全,效率高
3、可以存储null元素
4、默认初始化容量16,加载因子0.75
5、基于HashMap实现,底层使用HashMap保存所有元素 Key-value
常用方法
方法名 | 功能 |
---|---|
Iterator< E > iterator() | 得到当前列表的迭代器 |
int size() | 得到列表中元素的个数 |
boolean isEmpty() | 判断 HashSet() 集合是否为空,为空返回 true,否则返回false |
boolean contains(Object o) | 判断列表中是否有元素O |
boolean add(E e) | 如果当前列表中不存在e, 则将e加入列表 |
boolean remove(Object o) | 如果列表中存在元素O,则将其从列表中删除 |
void clear() | 从列表中删除所有元素 |
TreeSet
1、底层数据结构是红黑树(平衡二叉树)。(唯一,有序)
- 有序性:自然排序、比较器排序(使用元素的自然排序对元素进行排序,还是根据创建集合时提供的Comparator比较器进行排序,这取决于使用的构造方法。)
- 唯一性:根据比较的返回值是否是0来决定
- TreeSet不仅实现了Set接口,还实现了java.util.SortedSet接口。所以TreeSet实现的Set集合在遍历集合时按照自然顺序递增排序,也可以按照指定比较器递增排序。
自然排序:让元素所属的类中实现自然排序接口Comparerable接口 。可以在自定义类中实现Comparerable接口,重写compareTo()方法。
比较器排序:让集合的构造方法接收一个比较器Comparator接口的子类对象。可以在自定义类中实现Comparetor接口,重写compare()方法。
- Comparable接口:此接口强行对实现它的每个类的对象进行整体排序,这个排序称为自然排序。
- Comparable接口的方法:int compareTo(T o) 将此对象与指定的对象进行比较以进行排序。 参数 o - 要比较的对象。结果 负整数,零或正整数,对应该对象小于,等于或大于指定对象。
存储元素:
第一个元素存储的时候,直接作为根节点。
从第二个开始,每个元素从根节点开始比较,
大——就作为右孩子
小——就作为左孩子
相等——不搭理它
Map集合
1、map集合没有继承Collection接口,其提供的是Key到value的映射
2、Map中不能包含相同的Key。每个key只能映射一个value。即一个key对应一个value,不能存在相同的key但是可以存在相同的value
3、key还决定了存储对象在映射中的存储位置,通过一种“散列技术” 进行处理,产生一个散列码的整数值,散列码通常作为一个偏移量,该偏移量对应分配给映射的内存区域的起始位置,从而确定存储对象在映射中的存储位置。
Map接口定义的主要方法
方法名 | 功能 |
---|---|
put(K key,V value) | 向集合中添加指定的key-value的映射关系 |
containsKey(Object key) | 如果此映射包含指定的key的映射关系,则返回true |
containsValue(Object value) | 如果此映射将一个或多个key映射到指定值,则返回true |
get(Object key) | 如果存在指定的key对象,则返回该对象对应的值,否则返回null |
keySet() | 返回该集合中的所有key对象形成的set集合 |
value() | 返回该集合中所有值对象形成一个Collection集合 |
HashMap
1、HashMap是非同步的,HashMap中的对象是线程不安全的
2、并且允许null,即null value和null key,最多只能有一个null Key,但可以有无数个null value
3、建议使用HashMap类实现Map集合添加和删除映射关系效率高。
4、HashMap通过哈希码对其内部的映射关系进行快速查找。此类不保证映射的顺序,特别是他不保证该顺序永恒不变
5、HashMap 底层就是一个数组结构,数组中的每一项又是一个链表,当新建一个 HashMap 的时候,就会初始化一个数组。
HashMap的存取实现
存储:当程序试图将一个 key-value 对放入 HashMap 中时,程序首先根据该 key 的 hashCode() 返回值决定该 Entry 的存储位置:如果两 个 Entry 的 key 的 hashCode() 返回值相同,那它们的存储位置相同。
读取:从 HashMap 中 get 元素时,首先计算 key 的 hashCode,找到数组中对应 位置的某一元素,然后通过 key 的 equals 方法在对应位置的链表中找到需要的元素
TreeMap
1、TreeMap类不仅实现了map接口,还实现了java.util.SortedMap接口,因此,集合中的映射关系具有一定的顺序。
2、添加、删除和定位映射关系时,比HashMap类性能稍差
3、由于treemap类实现map集合中的映射关系是根据键对象按照一定的顺序排列的,影刺不允许键对象是Null
4、TreeMap 的实现是红黑树算法的实现
5、TreeMap是非线程安全的,只是用于单线程环境下
HashTable
1、Hashtable继承Map接口,实现一个key-value映射的哈希表。任何非空(non-null)的对象都可作为key或者value
2、HashTable是同步的,这个类 中的一些方法加入了synchronized关键字,保证了HashTable是线程安全的
3、HashTable不能存放空值
4、Hashtable的父类是Dictionary,HashMap的父类是AbstractMap
5、底层数据结构:哈希表(数组+链表)
6、无序性,不能保证插入有序
HashMap的方法实现
存储: put(K key, V value)
1.判断value是否为null;若为null抛出异常 ====》hashtable中value不能为null
2.通过key进行hash获取到key该存储的索引位置
3.该索引位置的链表进行遍历,获取key是否存在(key存在条件:hash是否相等,key使用equals())
4.在存在该key的情况下,将value值进行更新并且直接返回
5.key不存在则进行新节点插入
5.1 扩容考虑:(count >= threshold )entry结点个数大于扩容阈值;
5.2 新容量大小为:2 * table.length
5.3 将原哈希表中的数据全部进行重新hash到新的哈希表中
5.4 更新插入的key的新的位置
5.5 找到新节点的位置,创建entry实体通过头结点将元素进行插入
删除:remove(Object key)
1.通过key获取到当前存储的索引位置
2.对该索引位置下的链表进行遍历,找到key所对应的entry实体,并进行删除;
查找: get(Object key)
1.通过key的哈希获取到存储的索引位置 —》通过key为null进行get操作也会抛出异常
2.遍历当前索引位置下的结点,判断是否相等(hash、equals),找到则直接返回value值,未找到返回null