集合源码分析

1、集合分类

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fYIJ5yUq-1623802686029)(F:\typora\笔记图片\QQ截图20210509214623.png)]

2、Collection

集合特点:只能存放引用数据类型,基本数据类型会自动装箱变成包装类。

 /**Collection接口的常用方法:
        增加:add(E e) addAll(Collection<? extends E> c)将另一个集合添加入另一集合中
        删除:clear() 清空说有元素 remove(Object o)删除指定索引下标的元素
        查看:iterator()迭代器,遍历用  size()集合中的数量
        判断:contains(Object o)是否包含该元素  equals(Object o) isEmpty()是否为空
    */    
        Collection col = new ArrayList();
        List list = Arrays.asList(new Integer[]{2,6,4,8,9});
        col.addAll(list);//将另一个集合添加入col中
        //col.clear();清空集合
        System.out.println(col);
        System.out.println("集合中元素的数量为:"+col.size());
        System.out.println("集合是否为空:"+col.isEmpty());

迭代器

 public static void demo1() {
        Collection col = new ArrayList();
        col.add(12);
        col.add(13);
        col.add(1);
        col.add("ad");

        ArrayList list = new ArrayList();
        System.out.println(col);
        //增强for循环
       /* for (Object o : col) {
            System.out.println(o);
        }*/
        //迭代器遍历
        Iterator it = col.iterator();
        //hasNext判断迭代器是否有下一个元素
        while(it.hasNext()){
            //next获取迭代器当前位置元素,把指针指向下一元素
            System.out.println(it.next());
        }
    }

3、List

 /* List接口中常用方法:
        增加:add(int index, E element)
        删除:remove(int index)  remove(Object o)
        修改:set(int index, E element)
        查看:get(int index)
         */
         ArrayList<String> list = new ArrayList<>();
        list.add("aa");
        list.add("bb");
        list.add("cc");
        list.add("dd");
        /*list.set(0,"666");
        list.get(0);
        System.out.println(list);*/
        //集合遍历方式1迭代器
        Iterator it  = list.iterator();//返回该元素的迭代器
        while (it.hasNext()){//判断是否有下一元素
            System.out.println(it.next());//获取下一元素
        }
        // 方式2:普通for
        for (int i = 0; i < list.size() ; i++) {
            System.out.println(list.get(i));
        }
        //方式3:增强for
        for(String s:list){
            System.out.println(s);
        }

4、ArrayList源码分析

jdk1.7源码分析:底层是数组,数组长度初始化为10,扩容的时候扩容为原来的1.5倍。

    //ArrayList<E>继承AbstractList,实现List接口
    public class ArrayList<E> extends AbstractList<E>
    implements List<E>, RandomAccess, Cloneable, java.io.Serializable

    //ArrayList的父类 AbstractList也实现了List接口,重复实现了List接口
    public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> 

    //Default initial capacity.定义一个默认长度10的数组
    private static final int DEFAULT_CAPACITY = 10;

    //底层是Object类型的数组
    private transient Object[] elementData;

    //ArrayList的大小是它包含的元素个数
    private int size;

	//空参构造器给elementData赋值10
	public ArrayList() {
        super();
        this.elementData = EMPTY_ELEMENTDATA;
    }
    //调用带参构造器给数组elementData初始化,初始化长度为10
    public ArrayList(int initialCapacity) {
    super();
    if (initialCapacity < 0)
    throw new IllegalArgumentException("Illegal Capacity: "+
    initialCapacity);
    this.elementData = new Object[initialCapacity];
    }

    //add方法
    public boolean add(E e) {
    //当数组中的10个位置都满了的时候就开始进行数组的扩容,扩容长度为 原数组的1.5倍:
    ensureCapacityInternal(size + 1); //size+1=11 数组扩容操作
    elementData[size++] = e;//下标从0开始,添加元素后,下标+1
    return true;//添加成功放回true
    }
    //minCapacity为11,
    private void ensureCapacityInternal(int minCapacity) {
    //如果数组长度为空,就取最大值10
    if (elementData == EMPTY_ELEMENTDATA) {
    minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
    }
    //扩容方法
    ensureExplicitCapacity(minCapacity);
    }
    
    private void ensureExplicitCapacity(int minCapacity) {
    modCount++;
    if (minCapacity - elementData.length > 0) //11>10就扩容
    grow(minCapacity);// 生长、扩容
    }
    
    private void grow(int minCapacity) {//minCapacity11
    // overflow-conscious code
    int oldCapacity = elementData.length;	//oldCapacity为10
    int newCapacity = oldCapacity + (oldCapacity >> 1);	//新容器是原来的1.5倍
    if (newCapacity - minCapacity < 0)
    newCapacity = minCapacity;
    if (newCapacity - MAX_ARRAY_SIZE > 0)
    newCapacity = hugeCapacity(minCapacity);
    //将老数组中的元素复制到新数组中,然后返回新数组,elementData的指向由老数组指向新数组
    elementData = Arrays.copyOf(elementData, newCapacity); 	
    }

jdk1.8源码分析:底层仍是Object类型的数组,但在调用空参构造器的时候是初始化一个空数组,add方法

//底层是Object类型的数组
    private transient Object[] elementData;
    private int size;
    
    //调用空参构造给elementData初始化一个空数组{}
     public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }
	 private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
	
	//add方法
	 public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // size+1=1
        elementData[size++] = e;
        return true;
    }
    
   // ensureCapacityInternal 确保容量内部即确定容器大小
    private void ensureCapacityInternal(int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {//前面是个空数组,后面也是空数组
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);//10和1取最大值10,给minCapacity
        }

        ensureExplicitCapacity(minCapacity);//minCapacity 10
    }
    //minCapacity传入10
    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;
        // overflow-conscious code
        if (minCapacity - elementData.length > 0)	//10-0>0走grow方法
            grow(minCapacity);
    }
    
     private void grow(int minCapacity) {	//minCapacity 10
        // overflow-conscious code
        int oldCapacity = elementData.length;	//oldCapacity 0
        int newCapacity = oldCapacity + (oldCapacity >> 1);	//newCapacity 0
        if (newCapacity - minCapacity < 0)	//0-10<0
            newCapacity = minCapacity;	//newCapacity 10
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity);//将空数组复制到长度为10的新数组elementData中
    }

5、Vector

jdk1.8源码分析:底层也是Object类型的数组,初始化长度为10,扩容方法的新数组长度是老数组的2倍,add方法被synchronized修饰,线程安全。

protected Object[] elementData;
    protected int elementCount;
//    构造器
    public Vector(int initialCapacity) {
        this(initialCapacity, 0);
    }
     public Vector(int initialCapacity, int capacityIncrement) {
        super();
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        this.elementData = new Object[initialCapacity];	//初始化长度为10的数组
        this.capacityIncrement = capacityIncrement;
    }
    //add方法的扩容方法
    //synchronized修饰add方法,线程安全
    public synchronized boolean add(E e) {
        modCount++;
        ensureCapacityHelper(elementCount + 1);
        elementData[elementCount++] = e;
        return true;
    }
    private void ensureCapacityHelper(int minCapacity) {
        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }
    private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        //新数组长度是老数组的2倍
        int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
                                         capacityIncrement : oldCapacity);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

6、泛型

泛型ArrayList()是<>里面的E,E的类型不确定,但一定是引用数据类型。泛型的父类指定类型,子类就不需要指定类型,子类类型跟父类一样;如果父类不指定类型,那么子类也是泛型,在创建对象的时候才确定什么类型。泛型类可以定义多个参数类型,不同的泛型的引用类型不可以相互赋值。

泛型方法:这个方法的泛型的参数类型要和当前的类的泛型无关

public class TestGeneric<E> {
    //不是泛型方法 (不能是静态方法)
    public static void a(E e){
    }
    //是泛型方法
    public static <T>  void b(T t){
    }
}

通配符:?

泛型参数A和B是继承关系,但G和G不是继承关系,而是并列关系,G<?>是G和G的父类。

泛型受限

public class Person {
}
public class Student extends Person {
}
public class Demo5 {
    public static void main(String[] args) {
        List<Object> a = new ArrayList<>();
        List<Person> b = new ArrayList<>();
        List<Student> c = new ArrayList<>();
        //开始使用泛型受限,泛型上限--最大能接受的
       /* List<? extends Person>:
        就相当于:
        list1是   List<Person>--b的父类,是List<Person的子类>--Struden--c的父类
        继承Person,Person最大,所以上限就是Person最大,比Person大的类就会报错
        */
        List<? extends Person> list1 ;
        list1 = a; //  ?<=Person才可以  报错
        list1 = b;
        list1 = c;
        //开始使用泛型受限,泛型下限--Person最小,不能比Person小
        List<? super Person> list2;  //super要的是Persion往上的
        list2 = a;
        list2 = b;
        list2 = c; //  ?>=Person 报错
    }
}

7、LinkedList

7.1、常用方法

    增加 addFirst(E e) 添加头 addLast(E e) 追加到尾部
    offer(E e) 指定元素添加到尾部 offerFirst(E e) 添加到头 offerLast(E e)添加到尾
    删除 poll() 删除第一个元素
    pollFirst() 删除第一个元素,如果列表为空,则返回 null
    pollLast()  删除最后一个元素,如果此列表为空,则返回 null,JDK1.6以后新增方法,提高了代码的健壮性 
    removeFirst()  删除并返回第一个元素 removeLast() 删除并返回最后一个元素
    修改 set()
    查看 element() 查看第一个元素
    getFirst() 查看第一个元素  getLast() 查看最后一个元素
    indexOf(Object o)  返回此列表中指定元素的第一次出现的索引,如果此列表不包含元素,则返回-1lastIndexOf(Object o) 指定元素的最后一次出现的索引,如果此列表不包含元素,则返回-1peek() 查看第一个元素

7.2、LinkedList源码分析

底层是一个双向链表

transient int size = 0;	//集合中元素数量
public int size() {		//获取集合中元素数量
        return size;
    }
    transient Node<E> first;	//头结点
    transient Node<E> last;		//尾节点
    //add
    public boolean add(E e) {
        linkLast(e);  //添加的元素e
        return true;
    }
    void linkLast(E e) {
        final Node<E> l = last;	//将链表中的last节点给l,如果是第一个元素l为null
        final Node<E> newNode = new Node<>(l, e, null);	//将新增元素封装成一个Node对象
        last = newNode;		//将last节点指向新创建的节点
        if (l == null)		//如果添加的是第一个节点,将first指向新节点
            first = newNode;
        else
            l.next = newNode; //l的下一个节点指向新节点
        size++;			//集合中的元素增加1
        modCount++;
    }
    //指定索引的元素
    public E get(int index) {
        checkElementIndex(index);
        return node(index).item;
    }
    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;
        }
    }
    Node<E> node(int index) {
        // assert isElementIndex(index);
		//如果index<链表的一半,即链表的前半段
        if (index < (size >> 1)) {
            Node<E> x = first;	//头结点给x
            for (int i = 0; i < index; i++)	//从下标为0,开始查找index元素
                x = x.next;	//x指向下一节点
            return x;
        } else {		//链表的后半段
            Node<E> x = last;	//尾节点给x
            for (int i = size - 1; i > index; i--) //从size-1开始向前遍历
                x = x.prev;		x指向x的上一节点
            return x;			
        }
    }

8、Set

特点:唯一、无序

8.1、HashSet

特点:唯一、无序, 底层是 数组+链表 = 哈希表

PS:放入HashSet中的数据,一定要重写equal和hashCode方法

8.2、LinkedHashSet

特点:唯一、有序(按输入顺序输出), 哈希表+链表

在HashSet的基础上加了个总链表,将元素有序串在一起

8.3、TreeSet

特点:唯一、无序,有序,底层实现内部比较器或外部比较器。

比较器:用来排序使用,内部比较器A实现 Comparable接口,A类中重写CompareTo方法。外部比较器,把比较器写在A类的外面,B类实现 Comparable接口,重写CompareTo方法。外部比较器可以使用多态,可扩展性好。

9、Map

常用方法

    增加:put(K key, V value)返回值是个value
    删除:clear()清空所有 remove(Object key)删除key所在键值对
    查看:entrySet()得到的是key和value一对数据 get(Object key) keySet()获取key  size() map的大小 values() 获取值
    判断:containsKey(Object key) 是否包含key containsValue(Object value)是否包含value
    equals(Object o)值是否相等 isEmpty()是否为空

9.1HashMap源码分析

jdk1.7源码分析发生哈希冲突时,7上头插法,8下

public class HashMap<K,V> extends AbstractMap<K,V> //继承的AbstractMap实现过Map
    implements Map<K,V>, Cloneable, Serializable {
    
 	static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16,默认数组长度16
    static final int MAXIMUM_CAPACITY = 1 << 30;	//最大容量
    static final float DEFAULT_LOAD_FACTOR = 0.75f;	//默认的加载因子0.75
    transient Set<Map.Entry<K,V>> entrySet;		//主数组,每个元素为Entry类型
    transient int size;
    int threshold;		//数组扩容界限值,门槛值   16*0.75=12 
    final float loadFactor; //用来接收装填因子的变量,影响哈希表的因素

     public HashMap() {//空参构造器
        this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR);//this(16,0.75f)
    }
    
    public V put(K key, V value) {
        if (table == EMPTY_TABLE) {
            inflateTable(threshold);
        }
        if (key == null)
            return putForNullKey(value);
        int hash = hash(key);
        int i = indexFor(hash, table.length);
        for (Entry<K,V> e = table[i]; e != null; e = e.next) {
            Object k;
            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
                V oldValue = e.value;
                e.value = value;
                e.recordAccess(this);
                return oldValue;
            }
        }

        modCount++;
        addEntry(hash, key, value, i);
        return null;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值