集合是一个存储相同内容的容器。集合类主要由Map和Collection两个根接口派生而成。
在Collection下面有三个子接口来继承它,这三个子接口分别是List接口、Set接口和Queue接口。
List接口:
public interface List<E> extends Collection<E>
Set接口:
public interface Set<E> extends Collection<E>
Queue接口:
public interface Queue<E> extends Collection<E>
Map 接口下面的集合类主要由AbstractMap抽象类和SortedMap接口派生而来。比较常用的集合类有:HashMap,Hashtable,TreeMap,ConcurrentHashMap
AbstractMap抽象类:
public abstract class AbstractMap<K,V> implements Map<K,V>
SortedMap接口:
public interface SortedMap<K,V> extends Map<K,V>
常用集合类:
各类集合详解 :
List集合:
1、有序集合(存储和取出元素顺序相同)
2、有索引(可以使用普通for循环遍历)
3、元素可以重复(允许存储重复数据)
List集合下面有ArrayList、LinkedList、vector等子类他们的区别和联系有下表
ArrayList | LinkedList | Vector | |
底层数据结构 | 动态数组 | 双向循环链表 | 动态数组 |
特点 | 查询快,增删慢 | 查询慢,增删快 | 查询快,增删慢 |
线程安全性 | 不安全 | 不安全 | 安全 |
ArrayList :基于动态数组实现,容量能自动增长的集合。随机访问效率高,随机插入、随机删除效率低。线程不安全
动态数组:当数组容量不足以存放新的元素时,会创建新的数组,然后把原数组中的内容复制到新数组。
LinkedList:可以在任何位置进行插入和移除操作的有序集合,它是基于双向链表实现的,线程不安全。LinkedList 功能比较强大,可以实现栈、队列或双向队列。
Vector 是矢量队列,也是基于动态数组实现,容量可以自动扩容。跟 ArrayList 实现原理一样,但是 Vector 是线程安全,使用 Synchronized 实现线程安全,性能非常差,已被淘汰,使用 CopyOnWriteArrayList 替代 Vector。
ArrayList 和 Vector 区别
1、ArrayList 线程不安全,Vector 线程安全;
2、ArrayList 在扩容时默认是扩展为原来的1.5 倍+1,Vector 是默认扩展为原来的2倍;
3、ArrayList 支持序列化,Vector 不支持;
4、Vector 提供 indexOf(obj, start) 接口,ArrayList 没有;
5、Vector 构造函数可以指定扩容增加系数,ArrayList 不可以。
ArrayList 与 LinkedList 的区别
1、ArrayList 的数据结构是动态数组,LinkedList 的数据结构是链表;
2、ArrayList 不支持高效的插入和删除元素,LinkedList 不支持高效的随机访问元素;
3、ArrayList 的空间浪费在数组末尾预留一定的容量空间,LinkedList 的空间浪费在每一个结点都要消耗空间来存储 prev、next 等信息。
Set集合:
1、无序集合(存储和取出元素顺序不同)
2、无索引(不可以使用普通for循环遍历)
3、元素不可以重复(不允许存储重复数据)
List集合下面有HashSet、LinkedHashList、TreeSet等子类他们的区别和联系有下表
HashSet | LinkedHashSet | TreeSet | |
底层数据结构 | 哈希表(数组+链表或红黑树) | 链表+哈希表 | 红黑树 |
特点 | 查询快,增删快 | 查询快,增删快 | 查询快,增删快 |
保证唯一性方式 | 重写hashCode()和equals() | 重写hashCode()和equals() | CompareTo()返回0 |
线程安全性 | 不安全 | 不安全 | 不安全 |
HashSet:HashSet 是用来存储没有重复元素的集合类 ,底层是HashMap
LinkedHashSet:使用 HashSet 机制实现,由哈希表保证元素唯一,链表保证先进先出(FIFO)的插入顺序,它是一个可以保证插入顺序或是访问顺序的集合类
TreeSet:TreeSet 实现了 SortedSet 接口,意味着可以排序,它是一个有序的集合类,有两种比排序方式自然排序——继承Comparable接口实现compareTo方法和比较器排序——继承Comparator接口实现compare方法
HashSet、LinkedHashSet、TreeSet三者区别:
相同点:1)HashSet、LinkedHashSet、TreeSet都实现了Set接口
2)三者都保证了元素的唯一性,即不允许元素重复
3)三者都不是线程安全的
不同点:
1)排序,HashSet不保证元素的顺序;LinkHashSet保证FIFO即按插入顺序排序;TreeSet保证元素的顺序,支持自定义排序规则
2)null值,HashSet和LinkedHashSet允许添加null值;TreeSet不允许添加null值,添加null时会抛出
java.lang.NullPointerException
异常。3)性能,理论情况下,添加相同数量的元素, HashSet最快,其次是LinkedHashSet,TreeSet最慢(因为内部要排序)。
1)HashSet使用 :
HashSet的底层是HashMap,
private transient HashMap<E,Object> map;
HashSet类的代码声明如下:
public class HashSet<E>
extends AbstractSet<E>
implements Set<E>, Cloneable, java.io.Serializable
{...
可以看出HashSet是继承 AbstractSet抽象类 实现了 Set接口
1.1)添加元素:
public class myCollectionAdd {
public static void main(String[] args) {
//使用多态,创建一个HashSet对象
Collection<String> collection = new HashSet<>();
//输出该集合的内容为空的(重写toString方法)
System.out.println("重写了toString方法,但是没有对HashSet集合对象做任何操作,因此返回一个空的数组:"+collection);
// 往HashSet集合中添加元素使用add,返回值只一个boolean值,一般不用接收这个返回值
Boolean addReturn = collection.add("abc");
System.out.println("往集合中添加一个元素后的返回值:" + addReturn);
System.out.println("使用add方法往集合里面添加了元素后:" + collection);
//添加不同元素
System.out.println(collection.add("bcd"));
//无法添加重复元素
System.out.println(collection.add("abc"));
}
}
测试结果 :
重写了toString方法,但是没有对HashSet集合对象做任何操作,因此返回一个空的数组:[]
往集合中添加一个元素后的返回值:true
使用add方法往集合里面添加了元素后:[abc]
true
false
1.2) 获取元素:
HashSet没有获取元素的方法
1.3)获取元素个数
//获取元素个数
System.out.println("platformSet的元素个数为:" + collection.size());
测试结果 :
platformSet的元素个数为:2
1.4)删除元素
//删除元素
// 删除不存在的元素"qqq",返回false
System.out.println(collection.remove("qqq"));
// 删除存在的元素 "aaa",返回true
System.out.println(collection.remove("aaa"));
测试结果 :
false
true
1.5)判断集合是否为空
//判断集合是否为空
System.out.println("isEmpty:" + collection.isEmpty());
测试结果 :
isEmpty:false
1.6)修改元素
HashSet无法修改元素
1.7)遍历元素:两种方式Iterator迭代器和foreach
//遍历元素
System.out.println("使用Iterator遍历:");
Iterator<String> collectionIterator = collection.iterator();
while (collectionIterator.hasNext()){
System.out.println(collectionIterator.next());
}
System.out.println();
System.out.println("使用foreach遍历:");
for (String collectionStr: collection) {
System.out.println(collectionStr);
}
测试结果:
使用Iterator遍历:
bcd
abc
使用foreach遍历:
bcd
abc
1.8)清空集合
//清空集合
collection.clear();
2)LinkedHashSet 的使用
LinkedHashSet也是Set接口的实现类,底层数据结构是链表和哈希表,哈希表用来保证元素唯一,链表用来保证元素的插入顺序,即FIFO(First Input First Output 先进先出)。
LinkedHashSet类的代码声明如下所示:
public class LinkedHashSet<E>
extends HashSet<E>
implements Set<E>, Cloneable, java.io.Serializable {
{...}
从以上代码也能看出,LinkedHashSet类继承了HashSet类。
LinkedHashSet类的使用方法和HashSet基本一样,只需修改下声明处的代码即可:
Set<String> platformSet = new LinkedHashSet<>();
3)TreeSet的使用
TreeSet也是Set接口的实现类,底层数据结构是红黑树,TreeSet不仅保证元素的唯一性,也保证元素的顺序。
TreeSet类的代码声明如下所示:
public class TreeSet<E> extends AbstractSet<E>
implements NavigableSet<E>, Cloneable, java.io.Serializable
{
}
TreeSet类的使用方法和HashSet基本一样,只需修改下声明处的代码即可:
Set<String> platformSet = new TreeSet<>();
Map集合:
HashMap | Hashtable | TreeMap | ConCurrentHashMap | |
底层数据结构 | 数组+链表或红黑树(链表长度>8) | 数组+链表或红黑树(链表长度>8) | 红黑树 | 数组+链表或红黑树(链表长度>8) |
是否允许null键值 | 是 | 否 | 否 | 否 |
线程安全性 | 不安全 | 安全 | 不安全 | 安全 |
HashMap :是以key-value 键值对形式存储数据,允许 key 为 null(多个则覆盖),也允许 value 为 null。底层结构是数组 + 链表 + 红黑树。
Hashtable:Hashtable 也是一个哈希散列表,Hashtable 继承于 Dictionary,使用重入锁 Synchronized 实现线程安全,key 和 value 都不允许为 Null。HashTable 已被高性能的 ConcurrentHashMap 代替。
TreeMap :实现了 SotredMap 接口,意味着可以排序,是一个有序的集合。底层数据结构是红黑树结构,TreeMap 中的每个元素都存放在红黑树的节点上,默认使用自然排序,也可以自定排序,线程不安全。
ConCurrentHashMap:采用CAS + Synchronized 实现锁操作,Node 改名为 HashEntry,引入了红黑树保证查询效率,底层数据结构由数组 + 链表 + 红黑树组成,Node 数组默认为 16。
HashMap 与 Hashtable 的区别
- HashMap 线程不安全,效率高,HashTable 线程安全,效率低;
- HashMap 和 Hashtable 二者都实现了 Map 接口,HashMap 是继承于 AbstractMap,HashTable 继承于 Dictionary 类;
- HashMap 只允许一个 key 为 Null(多个则覆盖),允许多个 value 为 Null,HashTable 中的 key 和 value 都不允许为 null;
- 初始容量不一样,HashMap 默认 16,HashTabel 默认 11。
- 判断扩容顺序不一样,HashMap 是 put() 之后扩容,HashTabel 是 put() 之前扩容;
- 定位存储位置逻辑不一样,HashMap 是在 key.hashcode() 后使用位运算,HashTable 是在 key.hashcode() 后使用取模;
HashMap 与 TreeMap 的区别
- 数据结构不一样,HashMap 基于“数组 + 单链表”实现(达到一定条件时转为红黑树),TreeMap 基于红黑树实现 ;
- HashMap 随机存储,TreeMap 默认按 key 的字典升序排序;
- HashMap 只允许一个 key 为 Null(多个则覆盖),允许多个 value 为 Null,TreeMap 的 key 不允许为 Null,但允许多个 value 为 Null;
- HashMap 效率高,TreeMap 效率低。
HashMap 和 ConcurrentHashMap 的区别
1、HashMap和ConcurrentHashMap都是继承abstractMap抽象类,HashMap实现了Map接口,ConcurrentHashMap试下你了ConcurrentMap接口。
2、HashMap的线程不安全,ConcurrentHashMap的线程是安全的,这是因为ConcurrentHashMap通过CAS+synchronized锁,锁住只有当前操作的bucket,同时不影响其他线程操作其他bucket,效率高。
3、HashMap 只允许一个 key 为 Null(多个则覆盖),允许多个 value 为 Null,ConcurrentHashMap中的 key 和 value 都不允许为 null;
4、扩容算法不一样,HashMap是当键值对大于阈值则容量扩大到原来的2倍,ConcurrentHashMap是当键值对数量大于等于sizectl,单线程创建新哈希表,多线程复制bucket到新哈希表,扩容2倍。