1. java集合的种类
java的集合主要分为四种:List、Set、Queue、Map。
- List分为:
- ArrayList
- LinkedList
- Vector
- Set:
- HashSet
- TreeSet
- LinkedHashSet
- Queue:
- ArrayBlockingQueue
- LinkedBlockingQueue
- ...(不是重点)
- Map:
- HashMap
- TreeMap
- HashTable
2. List(有序)
1. ArrayList
ArrayList底层数据结构是基于数组实现的,因此他具有数组的特性:查询效率高、但增加和删除效率低。需要根据具体情况判断ArrayList是否合适。ArrayList在定义时不需要指定数组长度。
2. LinkedList
LinkedList底层是通过双向链表实现的,因此他也就具有链表的特性:查询效率低(需要遍历每一个节点),但增删效率高。
3. Vector
Vector的底层和ArrayList是一样的,通过数组来实现,但区别在于Vector是线程安全的,即支持线程同步。同一时间只允许一个线程对Vector进行操作,保证了在多线程情况下的数据一致性,但是在访问过程中就需要频繁的对Vector实例进行加锁和释放锁,所以读写效率会降低。
3. Set(无序)
Set是保存无序且不重复元素的,元素间不相等,而判断相等的条件是两个对象的HashCode值以及equals,两者同时满足相等则相等
1. HashSet
底层是基于HashMap来实现的,无序存放,存值允许为空,不允许重复。每当要存入一个对象时,会根据该对象的HashCode值进行一个算法的运算得到一个散列值,根据散列值进行存放。当出现散列值相等的情况时,会调用equals方法,如果依旧返回true则视为相同对象。
2. TreeSet
底层实际是TreeMap,是基于一个二叉树这样的一个数据结构,无序不可重复,无序是指存入和取出的顺序不一致。但是TreeSet支持有序排列。每添加一个新对象都会对二叉树进行一个排列再插入新值。
3. LinkedHashSet
继承于HashSet,所有的操作方法都与HashSet一致。只不过是个双向链表实现。
4. Map
1. HashMap
HashMap的结构是散列表,即数组加链表的形式。将链表挂载在数组上,数组的每一个元素都是一个链表的头节点。链表的每一个节点都包含有四个属性:Key、Value、Hash值和用于指向下一个节点的next指针(指针比较形象,但java中没有指针这一说法)。注意:在JDK1.8之中,HashMap的结构多了一个红黑树。则结构由数组加链表加红黑树组成。HashMap可以存储key不同但value相同的值,且Key和Value允许为空。
HashMap时非线程安全的,需要保证线程安全时可以使用SynchronizedMap或者ConcurrentHashMap。
HashMap不保证插入的顺序与查询的顺序一致,但每次查询的顺序是不变的。
HashMap结构与树化条件:
HashMap结构中的数组存在一个初始容量(capacity):16 。允许扩容,当数组的空间占用达到一个阈值时就会进行扩容,扩容为原数组容量的两倍。所以数组容量始终为2^n。而这个控制扩容的阈值是一个属性:负载因子 ,默认为0.75 。即每当数组的占用达到最大容量的0.75倍时就会扩容至原来的两倍。
当我们进行存值时,首先对key值调用重写过的HashCode方法,得到key的HashCode,再根据一个固定算法得到key 的哈希值。这个经过计算的哈希值大小一定是 0 ~ 数组容量的。所以就可以根据哈希值对应数组下标将该对象存储在数组上。但不排除会出现相同的哈希值的可情况,这个时候就称他为哈希冲突。当两个对象发生哈希冲突时则会对key调用equals方法比较值知否相等(这个equals方法是重写过的)。如果不相等则会以链式将该对象存储在搭载在数组的链表上,如果重复则会覆盖原值。当数组的容量至少扩容至64的前提下,这个时候如果某一链表的长度达到8就会将这个链表转换为红黑树结构。当红黑树的节点数小于6时就会恢复为链表形式。
2. HashTable
基本与HashMap一致,线程安全,但结构没有红黑树,且键值对都不允许为空。
2. TreeMap
基于二叉树数据结构存储数据。
HashMap和HashSet区别
- 前者实现了map接口和后者实现的是set接口;
- HashSet是通过HasMap来实现的,HashMap的输入参数由Key、Value两个组成;
而HashSet,只是输入key,value是常量。 - 两者处理重复元素时的方法不一样。
HashMap和HashTable区别
- 底层数据结构不同:jdk1.7底层都是数组+链表,但jdk1.8 HashMap加入了红黑树。
- Hashtable 是不允许键或值为 null 的,HashMap 的键值则都可以为 null。
- 添加key-value的hash值算法不同:HashMap添加元素时,是使用自定义的哈希算法,而HashTable是直接采用key的hashCode()
- 初始化容量不同:HashMap 的初始容量为:16,Hashtable 初始容量为:11,两者的负载因子默认都是:0.75。
- 扩容机制不同:当已用容量>总容量 * 负载因子时,HashMap 扩容规则为当前容量翻倍,Hashtable 扩容规则为当前容量翻倍 +1。