Java集合知识点

额,首先,因为基本都是左抄抄右抄抄,我都基本忘了从哪copy过来的了,只是为了方便自己复习,如果你看到有你的内容,请回复链接,我会注明转载。

1 总览

Collection 接口

  • Set 接口:无序,不可重复
  • List 接口:有序,可重复

Map 接口

  • 键值对
  • 不继承Collection
  • 键唯一
Map集合类 key为null Value为null
HashMap
TreeMap ×
ConcurrentMap × ×

img

123

2 List 接口

有序,可重复

list_method

位置访问方法

void add(int index, E e) // 将元素e插入到index处
boolean addAll(int index, Collection<? extends E> c)// 将集合c中所有元素插入到List集合的index处
E get(int index) // 返回index处的元素
E remove(int index) // 移除index处的元素
E set(int index, E e) // 将index处元素替换成e,并返回替换后的元素

查找

int indexOf(Object o) // 返回对象o再List中出现的位置
int lastIndexOf(Object o) // 返回对象o在List中最后一次出现的位置

范围查看

List subList(int fromIndex, int toIndex)//返回从fromIndex(包括)到toIndex(不包括)处所有元素集合组成的子集合

List迭代器

ListIterator<E> listIterator() // 返回List的ListIterator,初始位置索引为0
ListIterator<E> listIterator(int index) // 返回List的ListIterator,初始位置索引为index

ListIterator新增的方法

public interface ListIterator<E> extends Iterator<E> {
void add(E e); // 在游标 前面 插入一个元素(注意,是前面)
boolean hasPrevious(); // 判断游标前面是否有元素
int nextIndex(); // 返回游标后边元素的索引位置,初始为 0 
E previous(); // 返回游标前面的元素,同时游标前移一位。游标前没有元素就报 java.util.NoSuchElementException 的错
int previousIndex(); // 返回游标前面元素的位置,初始时为 -1,同时报 java.util.NoSuchElementException 错;
void set(E e); // r更新迭代器最后一次操作的元素为 E,也就是更新最后一次调用 next() 或者 previous() 返回的元素。当没有迭代,也就是没有调用 next() 或者 previous() 直接调用 set 时会报 java.lang.IllegalStateException 错
}

迭代器

public class Demo {
    public static void main(String[] args) {
        ArrayList<String> arr = new ArrayList<>();
        arr.add("a");
        arr.add("b");
        arr.add("c");
        arr.add("d");
        Iterator<String> iterator = arr.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
    }
}

List实现

implementation_of_the_list_interface.png

2.1 ArrayList

List接口的一个实现类,底层是数组

  • get、set快
  • remove、插入慢
  • add快

初始空间:默认10。复制其他数组时,开辟该数组空间的110%

空间扩展:原数组大小+原数组大小>>1

2.2 LinkedList

底层是双向循环链表

  • 末尾以外的地方添加、删除快
  • 大量查找,随机访问,慢

2.3 CopyOnWriteArrayList

写时复制,适用于读多写少

读写分离

写操作在一个复制的数组上进行,读操作还是在原始数组中进行,读写分离,互不影响。

写操作需要加锁,防止并发写入时导致写入数据丢失。

写操作结束之后需要把原始数组指向新的复制数组。

2.4 复杂度

Comparative.png

get:index已知,获取index位置的元素

contains:index未知,查找某一元素

3 Set 接口

无序,不可重复

implementtation_of_the_set_interface.png

6个实现类,2个接口

3.1 HashSet

a_hash_table_with_chained_overflow.png

  • 对象不可重复
  • 底层用HashMap实现,对象为键,值为标志位
  • 遍历使用HashMap的map.keySet().iterator()
  • 并发:不同步、线程不安全

3.2 LinkedHashSet

a_linked_hash_table.png

  • 底层使用LinkedHashMap实现
  • 链表使用双向链表实现(有序)
  • 用于有序消除重复元素(重写hashcode与equal)
  • 并发:不同步、线程不安全、迭代器快速失效

3.3 CopyOnWriteArraySet

  • 底层使用CopyOnWriteArrayList实现
  • 不适用于大量查找和插入操作
  • 适用于:白名单,黑名单,商品类目的访问和更新场景
  • 并发:线程安全、读写分离迭代器

3.4 EnumSet

初始化
enumset为抽象类,不可直接new
底层使用RegularEnumSet(long-64),或者JumboEnumSet(long数组)如果枚举值个数小于等于64,则静态工厂方法中创建的就是RegularEnumSet,大于64的话就是JumboEnumSet。
静态构造函数

<E extends Enum<E>> EnumSet<E> of(E first, E... rest)
// 创建包含指定元素的集合
<E extends Enum<E>> EnumSet<E> range(E from, E to)
//初始集合包括枚举值中指定范围的元素
<E extends Enum<E>> EnumSet<E> allOf(Class<E> elementType)
// 创建一个初始包含elementType中的所有元素的集合
<E extends Enum<E>> EnumSet<E> noneOf(Class<E> elementType)
// 创建一组元素类型,初始值为空

适用于求 交集、并集、补集

3.5 TreeSet

  • 底层算法使用 红黑树
  • 使用TreeMap类实现
  • 有序

并发:不同步、线程不安全、迭代器快速失效

补充:二叉树

只有两棵子树,度≤2

二叉树的性质

  1. 若二叉树的层次从0开始,则在二叉树的第i层至多有 2^i^个结点(i>=0)
  2. 高度为k的二叉树最多有2^k^ - 1个结点(k>=-1)(空树的高度为-1)
  3. 对任何一棵二叉树,如果其叶子结点数为m, 度为2的结点数为n, 则m = n + 1

二叉树的类型

二叉树的类型

类型 定义 图示
满二叉树 除最后一层无任何子节点外,每一层上的所有节点都有两个子节点,最后一层都是叶子节点。 img
完全二叉树 若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全二叉树。 img
平衡二叉树 又被称为AVL树,它是一颗空树或左右两个子树的高度差的绝对值不超过 1,并且左右两个子树都是一棵平衡二叉树。 img
二叉搜索树 又称二叉查找树、二叉排序树(Binary Sort Tree)。
它是一颗空树或是满足下列性质的二叉树:
1)若左子树不空,则左子树上所有节点的值均小于或等于它的根节点的值;
2)若右子树不空,则右子树上所有节点的值均大于或等于它的根节点的值;
3)左、右子树也分别为二叉排序树。
img
红黑树 是每个节点都带有颜色属性(颜色为红色或黑色)的自平衡二叉查找树,满足下列性质:
1)节点是红色或黑色;2)根节点是黑色;3)所有叶子节点都是黑色;4)每个红色节点必须有两个黑色的子节点。(从每个叶子到根的所有路径上不能有两个连续的红色节点。)5)从任一节点到其每个叶子的所有简单路径都包含相同数目的黑色节点。
img

遍历

  1. 前序遍历:根左右
  2. 中序遍历:左根右
  3. 后序遍历:左右根

img

前序遍历:A B C D E F G H K

中序遍历:B D C A E H G K F

后序遍历:D C B H K G F E A

分析如下

img

3.6 ConcurrentSkipListSet

插入图解:
modifying_a_linked_list.png
查找图解
searching_a_skip_list.png

  • 底层ConcurrentSkipListMap实现
  • 随机因子(用于随机选择level1的个数,线程安全的)
  • 确定层数:level设置默认为1,然后对rnd进行一个右位移操作后在与1进行与操作后来确定需要分为几层
  • cas保证线程安全

3.7 复杂度

comparative.png

4 Map 接口

键值对,不继承Collection,键唯一

Map方法

Map.png

Map实现

the_structure_of_map_implementation.png

4.1 HashMap

容量默认16

HashMap的bucket 数组大小一定是2的幂,若不是,寻找最近的的2的幂

结构如下

img

img

put方法流程

  1. 如果定位到的数组位置没有元素 就直接插入。
  2. 如果定位到的数组位置有元素就和要插入的key比较,如果key相同就直接覆盖,如果key不相同,就判断p是否是一个树节点,如果是就调用 e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value)将元素添加进入。如果不是就遍历链表插入(插入的是链表尾部)。

img

默认参数详解

为了减少hash值的碰撞,需要实现一个尽量均匀分布的hash函数,在HashMap中通过利用key的hashcode值,来进行位运算

img

public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable {
    // 序列号
    private static final long serialVersionUID = 362498820763181265L;    
    // 默认的初始容量是16
    static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;   
    // 最大容量
    static final int MAXIMUM_CAPACITY = 1 << 30; 
    // 默认的填充因子
    static final float DEFAULT_LOAD_FACTOR = 0.75f;
    // 当桶(bucket)上的结点数大于这个值时会转成红黑树
    static final int TREEIFY_THRESHOLD = 8; 
    // 当桶(bucket)上的结点数小于这个值时树转链表
    static final int UNTREEIFY_THRESHOLD = 6;
    // 桶中结构转化为红黑树对应的table的最小大小
    static final int MIN_TREEIFY_CAPACITY = 64;
    // 存储元素的数组,总是2的幂次倍
    transient Node<k,v>[] table; 
    // 存放具体元素的集
    transient Set<map.entry<k,v>> entrySet;
    // 存放元素的个数,注意这个不等于数组的长度。
    transient int size;
    // 每次扩容和更改map结构的计数器
    transient int modCount;   
    // 临界值 当实际大小(容量*填充因子)超过临界值时,会进行扩容
    int threshold;
    // 加载因子
    final float loadFactor;
}

4.2 LinkedHashMap

构造

public LinkedHashMap(int initialCapacity,float loadFactor,boolean accessOrder)

Hashmap实体中添加before,after(双向链表)实现有序访问
LinkedHashMap添加head、tail(头指针和尾指针)
accessOrder
accessOrder: 为 false按插入顺序访问;为true,按访问顺序访问(LRU算法)

LRU实现

protected boolean removeEldestEntry(Map.Entry<K,V> eldest)

可以重载该方法自己定义策略

是否线程安全

不安全,迭代器快速失效

4.3 ConcurrentHashMap

img

实现原理

1.7
采用乐观读+分段锁实现 来 实现ConcurrentMap
ConcurrentHashMap 是由 Segment 数组结构和 HashEntry 数组结构组成
Segment 实现了 ReentrantLock
1.8
采用CAS和synchronized来保证并发安全。数据结构跟HashMap1.8的结构类似,数组+链表/红黑二叉树。synchronized只锁定当前链表或红黑二叉树的首节点,这样只要hash不冲突,就不会产生并发,效率又提升N倍

其他

默认容量16
在获取size()会导致全锁,开销大
构造函数提供并发级别控制

4.4 复杂度

comparative.png

额,再次强调一次,因为基本都是左抄抄右抄抄,我都基本忘了从哪copy过来的了,只是为了方便自己复习,如果你看到有你的内容,请回复链接,我会加上去。

猜你喜欢

转载自www.cnblogs.com/zzfan/p/11594986.html