Java容器

Java容器参考链接

1.Collection

Collection 存储着对象的集合
在这里插入图片描述

1.1 Collection常用方法

方法名说明
boolean add(E e)向集合添加元素e,若指定集合元素改变了则返回true
boolean addAll(Collection<? extends E> c)把集合C中的元素全部添加到集合中,若指定集合元素改变返回true
void clear()清空所有集合元素
boolean contains(Object o)判断指定集合是否包含对象o
boolean containsAll(Collection<?> c)判断指定集合是否包含集合c的所有元素
boolean isEmpty()判断指定集合的元素size是否为0
boolean remove(Object o)删除集合中的元素对象o,若集合有多个o元素,则只会删除第一个元素
boolean removeAll(Collection<?> c)删除指定集合包含集合c的元素
boolean retainAll(Collection<?> c)从指定集合中保留包含集合c的元素,其他元素则删除
int size()集合的元素个数
T[] toArray(T[] a)将集合转换为T类型的数组

1.2 常用分类

List 接口:元素按进入先后有序保存,可重复

  • ArrayList:基于动态数组实现,支持随机访问,没有同步,线程不安全
  • Vector:和 ArrayList 类似基于数组,同步,线程安全
  • LinkedList:基于双向链表实现,只能顺序访问,但是可以快速地在链表中间插入和删除元素。不仅如此,LinkedList 还可以用作栈、队列和双向队列。

Set 接口: 仅接收一次,不可重复,并做内部排序

  • TreeSet:基于红黑树实现,支持有序性操作,例如根据一个范围查找元素的操作。但是查找效率不如 HashSet,HashSet 查找的时间复杂度为 O(1),TreeSet 则为 O(logN)。
  • HashSet:基于哈希表实现,支持快速查找,但不支持有序性操作。并且失去了元素的插入顺序信息,也就是说使用 Iterator 遍历 HashSet 得到的结果是不确定的。
  • LinkedHashSet:具有 HashSet 的查找效率,并且内部使用双向链表维护元素的插入顺序。

1.3 List

(1)ArrayList:底层数据结构是数组,查询快,增删慢,线程不安全,效率高,可以存储重复元素
(2)LinkedList 底层数据结构是链表,查询慢,增删快,线程不安全,效率高,可以存储重复元素
(3)Vector:底层数据结构是数组,查询快,增删慢,线程安全,效率低,可以存储重复元素
在这里插入图片描述

1.3.1 ArrayList

ArrayList分析

1.3.2 Vector

Vector和CopyOnWriteArrayList分析

1.3.3 LinkedList

LinkedList分析

1.4 Set

HashSet分析
LinkedHashSet分析
TreeSet分析

2. Map

在这里插入图片描述
主要方法:

public int size() //当前Map的大小
public boolean isEmpty()//查询Map是否为空
public boolean containsValue(Object value)//查询Map中是否包含指定value
public boolean containsKey(Object key)
public V get(Object key)//返回指定key对应的value,如果不包含key返回null
public V put(K key, V value)
public V remove(Object key)//删除key所对应的的键值对,返回所关联的value,如果key不存在返回null
public void putAll(Map<? extends K, ? extends V> m)
public void clear()
public Set<K> keySet()//返回该Map中所有key组成的set集合
public Collection<V> values()//返回Map所有value组成的Collection
public Set entrySet()//返回Map中所包含的键值对组成的Set集合,每个集合元素都是Map.Entry对象

LinkedHashMap

  1. 存储结构
    继承自 HashMap,因此具有和 HashMap 一样的快速查找特性。
public class LinkedHashMap<K,V> extends HashMap<K,V> implements Map<K,V>

内部维护一个双向链表,用来维护插入顺序或者LRU顺序(最近最晚被使用)

/**
 * The head (eldest) of the doubly linked list.
 */
transient LinkedHashMap.Entry<K,V> head;

/**
 * The tail (youngest) of the doubly linked list.
 */
transient LinkedHashMap.Entry<K,V> tail;

accessOrder 决定了顺序,默认为 false,此时维护的是插入顺序。LinkedHashMap 最重要的是以下用于维护顺序的函数,它们会在 put、get 等方法中调用。

void afterNodeAccess(Node<K,V> p) { }
void afterNodeInsertion(boolean evict) { }

afterNodeAccess()
当一个节点被访问时,如果 accessOrder 为 true,则会将该节点移到链表尾部。也就是说指定为 LRU 顺序之后,在每次访问一个节点时,会将这个节点移到链表尾部,保证链表尾部是最近访问的节点,那么链表首部就是最近最久未使用的节点。

// 这个方法的作用就是将刚访问过的元素放到集合的最后一位
void afterNodeAccess(Node < K, V > e) { 
    LinkedHashMap.Entry < K, V > last;
    if (accessOrder && (last = tail) != e) {
        // 将 e 转换成 LinkedHashMap.Entry
        // b 就是这个节点之前的节点
        // a 就是这个节点之后的节点
        LinkedHashMap.Entry < K, V > p = (LinkedHashMap.Entry < K, V > ) e, b = p.before, a = p.after;

        // 将这个节点之后的节点置为 null
        p.after = null;

        // b 为 null,则代表这个节点是第一个节点,将它后面的节点置为第一个节点
        if (b == null) head = a;
        // 如果不是,则将 a 上前移动一位
        else b.after = a;
        // 如果 a 不为 null,则将 a 节点的元素变为 b
        if (a != null) a.before = b;
        else last = b;
        if (last == null) head = p;
        else {
            p.before = last;
            last.after = p;
        }
        tail = p;
        ++modCount;
    }
}

afterNodeInsertion()
在 put 等操作之后执行,当 removeEldestEntry() 方法返回 true 时会移除最晚的节点,也就是链表首部节点 first。
evict 只有在构建 Map 的时候才为 false,在这里为 true。

void afterNodeInsertion(boolean evict) { // possibly remove eldest
    LinkedHashMap.Entry<K,V> first;
    if (evict && (first = head) != null && removeEldestEntry(first)) {
        K key = first.key;
        removeNode(hash(key), key, null, false, true);
    }
}

removeEldestEntry() 默认为 false,如果需要让它为 true,需要继承 LinkedHashMap 并且覆盖这个方法的实现,这在实现 LRU 的缓存中特别有用,通过移除最近最久未使用的节点,从而保证缓存空间足够,并且缓存的数据都是热点数据。

protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
    return false;
}

LRU缓存
以下是使用 LinkedHashMap 实现的一个 LRU 缓存:
设定最大缓存空间 MAX_ENTRIES 为 3;
使用 LinkedHashMap 的构造函数将 accessOrder 设置为 true,开启 LRU 顺序;
覆盖 removeEldestEntry() 方法实现,在节点多于 MAX_ENTRIES 就会将最近最久未使用的数据移除。

class LRUCache<K, V> extends LinkedHashMap<K, V> {
    private static final int MAX_ENTRIES = 3;

    protected boolean removeEldestEntry(Map.Entry eldest) {
        return size() > MAX_ENTRIES;
    }

    LRUCache() {
        super(MAX_ENTRIES, 0.75f, true);
    }
}
public static void main(String[] args) {
    LRUCache<Integer, String> cache = new LRUCache<>();
    cache.put(1, "a");
    cache.put(2, "b");
    cache.put(3, "c");
    cache.get(1);
    cache.put(4, "d");
    System.out.println(cache.keySet());
}

借鉴链接:LruCache详解

Question:

Q: Java集合框架中有哪些类?都有什么特点
Q:集合、数组、泛型的关系,并比较
Q: ArrayList和Linklist的区别?
Q: ArrayList和Vector的区别?
Q: HashSet和TreeSet的区别?
Q: HashMap和Hashtable的区别?
Q: HashMap在put、 get元素的过程?体现了什么数据结构?
Q:如何解决Hash冲突?
Q:如何保证HashMap线程安全?什么原理?
Q: HashMap是有序的吗?如何实现有序?
Q: HashMap是如何扩容的?如何避免扩容?
Q: hashcode的作用, 与equal有什么区别?

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值