文章目录
一、Java集合框架图
二、Collection集合
1.java.util.Collection接口
Collection接口是整个Java类集中保存单值的最大操作父接口,里面每次操作的时候只能保存一个对象的数据。
此接口定义如下:
public interface Collection<E> extends Iterable<E>
此接口常用方法:
No. | 方法名称 | 描述 |
---|---|---|
1 | public boolean add(E e) | 向集合中插入一个元素 ,即将e看作一个整体 |
2 | public boolean addAll(Collection<? extends E> e) | 向集合中插入一组元素,即将e中元素添加进去,各是各 |
3 | public void clear() | 清空集合中的元素 |
4 | public boolean contains(Object o) | 判断o是否存在于集合中 |
5 | public boolean containsAll(Object o) | 判断o是否是当前集合的子集 |
6 | public boolean isEmpty() | 判断集合是否为空 |
7 | public Iterator<E> iterator() | 为Iterator接口实例化 |
8 | public boolean remove(Object o) | 从集合中删除一个对象o |
9 | boolean removeAll(Collection<?> e) | 删除多个,删除交集 |
10 | public int size() | 返回集合中元素个数 |
11 | public Object[] toArray() | 以对象数组的形式返回集合中全部内容 |
12 | <T>T[] toArray(T[] a) | 指定操作的泛型类型,并把内容返回 |
13 | public boolean equals(Object o) | 从Object类中重写而来 |
14 | public int hashCode() | 从Object类中重写而来 |
15 | boolean retainAll(Collection<?> e) | 判断是否没有指定的集合 |
2.List接口
在整个集合中List是Collection的子接口,里面的所有内容都是允许重复的。
List子接口的定义:
public interface List<E> extends Collection<E>
List子接口对于Collection的扩展方法:
No. | 方法名称 | 描述 |
---|---|---|
1 | public void add(int index,E element) | 在index处添加元素element |
2 | boolean addAll(int index,Collection<? extends E> e) | 在index处添加一组元素 |
3 | public E get(int index) | 取出index处的元素 |
4 | public int indexOf(Object o) | 返回o的位置,没有返回-1 |
5 | public int lastIndexOf(Object o) | 返回最后一个o的位置,没有返回-1 |
6 | public ListIterator<E> listIterator() | 返回ListIterator接口的实例 |
7 | public ListIterator<E> listIterator(int index) | 返回inedx的ListIterator实例 |
8 | public E remove(int index) | 删除index处的内容并返回 |
9 | public E set(int index,E element) | 修改index处的内容为element |
10 | List<E> subList(int fromIndex,int toIndex) | 返回子集合 |
2.1 ArrayList
底层使用数组结构,对于增加删除操作慢,查找快。
线程不安全的
默认扩容为原来的1.5倍
ArrayList的源码分析:
/*
1.用空参构造器new一个ArrayList实例时,默认创建一个长度为0的空数组
*/
transient Object[] elementData;//存储元素的数组
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
/*
2.当第一次使用add(E e)时,扩容长度为10
*/
public boolean add(E e) {
modCount++;
add(e, elementData, size);
return true;//此处永远返回true,与添加成功或失败无关
}
private void add(E e, Object[] elementData, int s) {//e是要添加的元素,elementData是存储元素的数组,s是有效元素个数
if (s == elementData.length)
elementData = grow();
elementData[s] = e;
size = s + 1;
}
/*
扩容
*/
private int newCapacity(int minCapacity) {//minCapacity是size+1
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);//新数组长度是原数组长度的1.5倍
if (newCapacity - minCapacity <= 0) {//新数组长度仍然不够
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA)//数组为空
return Math.max(DEFAULT_CAPACITY, minCapacity);//返回两者之间的大数,DEFAULT_CAPACITY是10
if (minCapacity < 0)
throw new OutOfMemoryError();
return minCapacity;//既不是默认长度,也不溢出,返回size+1长度,刚好够存
}
return (newCapacity - MAX_ARRAY_SIZE <= 0)//MAX_ARRAY_SIZE是int类型最大值-8
? newCapacity
: hugeCapacity(minCapacity);
}
2.2 Vector
Vector使用的是数组结构
线程安全的
Vector的源码分析:
//add(E e)同ArrayList一致
private int newCapacity(int minCapacity) {
int oldCapacity = elementData.length;
//若扩容增量<=0(默认为0),扩容为原来的长度*2;
//若增量不为0,扩容为旧数组长度+增量
int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
capacityIncrement : oldCapacity);
if (newCapacity - minCapacity <= 0) {
if (minCapacity < 0)
throw new OutOfMemoryError();
return minCapacity;
}
return (newCapacity - MAX_ARRAY_SIZE <= 0)
? newCapacity
: hugeCapacity(minCapacity);
}
2.3 LinkedList
LinkedList底层使用了双向链表结构,对于增删快,查找慢
他提供了丰富的API,可以将其当做栈、队列、双端队列等各种数据结构
3.Set接口
Set 集合中不包含重复元素(包括null),即不可能有e1和e2,且e1.equals(e2)==true
3.1 HashSet
HashSet:散列存放(哈希表)
不能存储重复元素
不保证存储顺序
线程不安全的
可以存储null
3.1.1 LinkedHashSet
是HashSet的子类
存储时无序
不能存储重复元素
用链表维护了两个变量,记录此数据的前后数据,这使得存储效率低于HashSet;但频繁的遍历操作,效率高于HashSet
3.3 TreeSet
TreeSet底层是红黑树
线程不安全
不能存储重复元素
若存储的为自定义类型,要去实现Comparable接口,并实现他的compareTo()方法;或实现Comparator接口。可按照指定属性的大小排序,当指定属性比较return 0时,认为是相同元素。
三、Map
一组键值对,映射关系
key:无序,不可重复。key所在的类一定要重写equals()和hashcode()
value:无序的,可重复的
一个key-value键值对,构成了一个Entry对象,无序不可重复
Map接口常用方法:
No. | 方法名称 | 描述 |
---|---|---|
1 | void clear() | 清空所有 |
2 | boolean containsKey(Object key) | 判断集合中是否存在key |
3 | boolean containsValue(Object value) | 是否包含value |
4 | V get(Object key) | 根据key获取value |
5 | boolean isEmpty() | 判断map是否为空 |
6 | Set<K> keySet() | 将map的key作为一个Set集合返回 |
7 | V put(K key, V value) | 如果已存在key,用新值替换旧值,返回旧值;如果不存在替换,返回null |
8 | V remove(Object key) | 返回被删除的数据,若没有关联,返回null |
9 | boolean remove(Object key, Object value) | 当key-value匹配时才删除 |
10 | void putAll(Map<? extends K,? extends V> m) | 将另一个map中的所有映射关系都添加到当前map中,各是各 |
11 | int size() | 返回map中键值对的个数 |
12 | Collection<V> values() | 将所有的值作为一个集合返回 |
1. HashMap
1.1 LinkedHashMap
是HashMap的子类,在遍历时可以保证添加顺序,在HashMap底层结构基础上,添加了一堆指针,指向前后元素
2. TreeMap
按照key排大小顺序,底层是红黑树
依据key的大小,认为大小相等的两个key就是重复的。要么key类型本身实现了java.lang.Comparable;要么创建TreeMap时,指定一个java.util.Comparator接口的实现类对象
四、JDK9集合新特性
创建固定长度的集合
List.of()
Set.of()
Map.of()
五、总结
1.Set添加元素时用add(),是作为底层的Map的key。value选用了一个Object类型的常量对象PRESENT。
2.ArrayList和Vector的区别?
Vector
:最早版本的动态数组(旧版),线程安全的(有线程同步的),不够后扩容为原来的2倍,初始容量10,支持的遍历集合的方式有foreach,Iterator,支持旧版Enumeration迭代器
ArrayList
:相对Vector来说新一点,线程不安全的(没有线程同步的),不够后扩容为原来的1.5倍,初始容量10(JDK1.6),支持foreach,Iterator
2倍:造成空间浪费的可能性比较大
1.5倍:造成扩容的次数增大
如果能预估元素个数,初始化时,直接在构造器初始化
3.HashMap、HashTable、ConcurrentHashMap的区别?
HashMap:线程不安全,效率高。允许存null的key和value。
HashTable:线程安全,效率低。不允许key和value是null
ConcurrentHashMap:采用分段锁机制,保证线程安全,效率又比较高
4.散列因子越大,越节省空间,但查询效率越低;散列因子越小,越浪费空间,但查询效率越高