java 集合 必读源码

Collection概念 - 容器

有序集合

List是有序的Collection 实现类ArrayList Vector LinkedList

​ 外部做同步操作

List list = Collections.synchronizedList(new LinkedList(...));

ArrayList

  • 基于数组,在数组中搜索和读取数据是很快的。因此 ArrayList 获取数据的时间复杂度是O(1);
  • 但是添加、删除时该元素后面的所有元素都要移动,所以添加/删除数据效率不高;
  • 另外其实还是有容量的,每次达到阈值需要扩容,这个操作比较影响效率。

LinkedList

  • 基于双端链表,添加/删除元素只会影响周围的两个节点,开销很低;
  • 只能顺序遍历,无法按照索引获得元素,因此查询效率不高;
  • 没有固定容量,不需要扩容;
  • 需要更多的内存,如文章开头图片所示 LinkedList 每个节点中需要多存储前后节点的信息,占用空间更多些。
  1. ArrayList

    原理: 底层是基于数组来实现容量大小动态变化的 使用了System.arrayCopy()数组拷贝

    // 构造一个空列表的初始容量10。  
    ArrayList(Collection<? extends E> c) 
    // 构造一个包含指定集合的元素的列表,它们的顺序返回的集合的迭代器。  
    ArrayList(int initialCapacity) 
    // 构造一个与指定初始容量的空列表。 
    
    
    // 默认大小
    private static final int DEFAULT_CAPACITY = 10;
    // 底层是Object数组,ArrayList比泛型出现早
    transient Object[] elementData; 
    // 实际有多少个元素
    private int size; // elementData.length 为集合容量
    // 继承父类AbstractList 记录操作数  主要使用是在 Iterator,是防止在迭代的过程中集合被修改
    protected transient int modCount = 0;
    // 有参构造
    private static final Object[] EMPTY_ELEMENTDATA = {};
    // 空参构造
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
    
    // 第一次添加元素时容量扩大至 10 的。
    public ArrayList() {this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;}
    public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {this.elementData = new Object[initialCapacity];} 
        else if (initialCapacity == 0) {this.elementData = EMPTY_ELEMENTDATA;} 
        else {throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity);}//不合法的参数异常
        }
    public ArrayList(Collection<? extends E> c) {
        Object[] a = c.toArray();
        if ((size = a.length) != 0) {//集合容量
            if (c.getClass() == ArrayList.class) {//判断传入集合是不是ArrayList
                elementData = a;
            } else {//不是ArrayList就复制
                elementData = Arrays.copyOf(a, size, Object[].class);
                }
            } else {
               elementData = EMPTY_ELEMENTDATA;
            }
        }
    
    public boolean add(E e) {
            modCount++;
            add(e, elementData, size);//private void add(E e, Object[] elementData, int s)
            return true;
        }
    private void add(E e, Object[] elementData, int s) {
            if (s == elementData.length)
                elementData = grow();//private Object[] grow()
            elementData[s] = e;
            size = s + 1;
        }
    private Object[] grow() {
            return grow(size + 1);//private Object[] grow(int minCapacity)
        }
    private Object[] grow(int minCapacity) {
            return elementData = Arrays.copyOf(elementData, newCapacity(minCapacity));// 扩容
        }
    private int newCapacity(int minCapacity) {
            int oldCapacity = elementData.length;
            int newCapacity = oldCapacity + (oldCapacity >> 1);
            if (newCapacity - minCapacity <= 0) {
                if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
                    return Math.max(DEFAULT_CAPACITY, minCapacity);// 扩容
                if (minCapacity < 0) // overflow
                    throw new OutOfMemoryError();
                return minCapacity;
            }
            return (newCapacity - MAX_ARRAY_SIZE <= 0)
                ? newCapacity
                : hugeCapacity(minCapacity);
        }
    

    2.Vector 与 ArrayList 原理相同 只是加上 synchronized

    ​ 区别 : Vector线程安全 ArrayList线程不安全

    3.LinkedList 线程不安全

    ​ 原理 : 双向链表实现

     public LinkedList() {}
     public LinkedList(Collection<? extends E> c) { this(); addAll(c); }
    
    transient int size = 0;
    transient Node<E> first;//头节点
    transient Node<E> last;//尾节点
    
     // 内部类  双向链表
    private static class Node<E> {
            E item;
            Node<E> next;
            Node<E> prev;
            Node(Node<E> prev, E element, Node<E> next) {
                this.item = element;
                this.next = next;
                this.prev = prev;
            }
        }
    
    // 迭代器 线程不安全 (并发修改异常,与ArrayList类似)
    ListItr(int index) {
                next = (index == size) ? null : node(index);
                nextIndex = index;
            }
    //倒序迭代器
    private class DescendingIterator implements Iterator<E> {
            private final ListItr itr = new ListItr(size());
            public boolean hasNext() {
                return itr.hasPrevious();
            }
            public E next() {
                return itr.previous();
            }
            public void remove() {
                itr.remove();
            }
        }
    

    有序不重复

    1.TreeSet

    ​ 原理 : 二叉树 , 对于新添加的对象按照指定的顺序排序 , 每添加一个对象都会排序 , 并插入二叉树指定位置

    TreeSet是一个有序的集合,它的作用是提供有序的Set集合。它继承了AbstractSet抽象类,实现了NavigableSet,Cloneable,Serializable接口。

    TreeSet是基于TreeMap实现的,TreeSet的元素支持2种排序方式:自然排序或者根据提供的Comparator进行排序。

    Integer和String等基础对象 , TreeSet默认排序存储 , 自定义类型必须实现Comparable接口 , 重写compareTo方法 , 升序 this - 对象 == -1 降序 this - 对象 == 1

      TreeSet(NavigableMap<E,Object> m) {
            this.m = m;
        }
        public TreeSet() {
            this(new TreeMap<>());
        }
        public TreeSet(Comparator<? super E> comparator) {
            this(new TreeMap<>(comparator));
        }
        public TreeSet(Collection<? extends E> c) {
            this();
            addAll(c);
        }
        public TreeSet(SortedSet<E> s) {
            this(s.comparator());
            addAll(s);
        }
    
    public class Person implements Comparable<Person> {
        private String name;
        private int age;
        ...
        public int compareTo(Person o) {
            return 0;                //当compareTo方法返回0的时候集合中只有一个元素
            return 1;                //当compareTo方法返回正数的时候集合会怎么存就怎么取
            return -1;                //当compareTo方法返回负数的时候集合会倒序存储
        }
    }
    
    //定义一个类,实现Comparator接口,并重写compare()方法,
    class CompareByLength implements Comparator<String> {
    
        @Override
        public int compare(String s1, String s2) {        //按照字符串的长度比较
            int num = s1.length() - s2.length();        //长度为主要条件
            return num == 0 ? s1.compareTo(s2) : num;    //内容为次要条件
        }
    }
    

    2 . LinekdHashSet 继承于HashSet

    原理 : 底层使用LinkedHashMap

    无序集合

    Set是无序的Collection 实现类HashSet TreeSet LinkHashSet

    核心特性 : 存储无序且值不相等

    1.HashSet

    ​ 原理 : HashMap的数据存储是通过数组+链表/红黑树实现的,存储大概流程是通过hash函数计算在数组中存储的位置,如果该位置已经有值了,判断key是否相同,相同则覆盖,不相同则放到元素对应的链表中,如果链表长度大于8,就转化为红黑树,如果容量不够,则需扩容

    ​ HashSet 存放的是散列值 按照元素的散列值存取元素 (HashMap)

    ​ HashSet 先判断HashCode 如果HashCode相等 再通过equals方法判断 所以判断对象 需要重写HashCode方法和equals方法

    private transient HashMap<E,Object> map;
    //默认构造器
    public HashSet() {
        map = new HashMap<>();
    }
    //将传入的集合添加到HashSet的构造器
    public HashSet(Collection<? extends E> c) {
        map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
        addAll(c);
    }
    //明确初始容量和装载因子的构造器
    public HashSet(int initialCapacity, float loadFactor) {
        map = new HashMap<>(initialCapacity, loadFactor);
    }
    //仅明确初始容量的构造器(装载因子默认0.75)
    public HashSet(int initialCapacity) {
        map = new HashMap<>(initialCapacity);
    }
    
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值