集合框架学习

集合框架图

在这里插入图片描述注意:虚线对应的是接口,实线对应的是实现类

顶层的接口:Collection 和 Map

接口是为了提供方法
Collection接口表示存储的是单个数据组成的集合;
Map接口表示存储的是key-value键值对的集合。

public class CollectionTest {
    public static void main(String[] args) {
        //ArrayList是Collection的实现类:存储的是单一元素
        ArrayList<Integer> arrayList = new ArrayList<Integer>();
        arrayList.add(23);
        arrayList.add(45);

        //HashMap是Map接口实现类:key-value键值对
        HashMap<String,String> hashMap =  new HashMap<String,String>();
        hashMap.put("k1","v1");
    }
}

1:Collection的三个子接口:
List:允许存储重复的元素的集合;
Set:不允许存储重复的元素的集合(去重);
Queue:主要是用于存储数据,模拟队列(先进先出)模拟栈(先进后出)、优先级队列;可以重复;

2:Map接口:存储的是键值对
SortMap:对于元素进行排序

实现类特点

1:List接口的实现类:
ArrayList:查询速度快,底层基于数组来存储元素,封装一个动态的Object[]数组,是一种顺序存储的集合(插入有序);
LinkedList:增删速度快,线程不安全,底层是一个双向链表实现,元素也是插入有序;
Vector:线程安全。查询增删速度慢,已经被ArrayList替代。

2:Set接口的实现类:
HashSet:底层数据结构是基于HashMap实现的,线程不安全,不保证集合中元素顺序,即不能保证数据和插入顺序一致
LinkedSet:底层数据结构是基于LinkedHashMap实现,线程不安全,能保证数据和插入顺序一致
TreeSet:基于TreeMap集合实现,线程不安全,数据是有序的(按照属性的特征排序)

3:Map接口的实现类:存储的是键值对
HashMap:底层是一个哈希表结构,线程不安全,允许Key-Value为null,key不能重复(哈希表结构相关)
HashTable:和HashMap类似,底层是哈希表接口,线程安全,Key-Value不能为null
LinkedHashMap:是HashMap的子类,可以保证数据插入是有序的
TreeMap:底层是二叉树:红黑树,线程不安全,数据可以基于属性特征排序

Collection接口提供的方法

在这里插入图片描述
在线JDK方法在这里插入图片描述

   ArrayList<Integer> arrayList = new ArrayList<Integer>();
        /**
         * 添加单个元素
         * boolean add(E e)
         * 返回值Boolean类型   true:插入成功  false:插入失败
         */
        arrayList.add(23);
        arrayList.add(45);

        ArrayList<Integer> list = new ArrayList<>();
        list.add(12);
        list.add(15);
        list.add(17);
        HashSet<Integer> hashSet = new HashSet<>();
        hashSet.add(55);
        hashSet.add(78);
        /**
         * 批量添加元素
         * boolean addAll(Collection<? extends E> c)
         * 返回值Boolean类型   true:插入成功  false:插入失败
         */
        arrayList.addAll(hashSet);

        for (Integer i : arrayList) {
            System.out.print(i + " ");
        }
        System.out.println();
        System.out.println("------");

        /**
         * 删除集合中元素
         * void clear()
         */
//        arrayList.clear();
//        for (Integer i:arrayList) {
//            System.out.print(i+" ");
//        }
        /**
         * 判断当前集合是否包含指定元素
         * boolean contains(Object o)
         * 返回值Boolean类型   true:存在  false:不存在
         */
        boolean b = arrayList.contains(55);
        System.out.println(b);
        /**
         * 判断集合是否为空
         * boolean isEmpty()
         */
        boolean empty = arrayList.isEmpty();
        System.out.println(empty);

        /**
         * 利用迭代器遍历集合
         * 迭代器是一种设计模式,主要作用是用来遍历容器/集合而不暴露集合内部的内部实现细节
         *Iterator<E> iterator()
         * 返回是Iterator类型对象
         * 该类型下提供方法:
         * hasNext():判断容器中是否还存在下一个元素
         * next():获取当前元素
         */
        Iterator<Integer> iterator = arrayList.iterator();
        while (iterator.hasNext()) {
            Integer value = iterator.next();
            System.out.print(value+" ");
        }
        System.out.println();
        System.out.println("-----");

        /**
         * for( : )
         * foreach遍历底层还是使用迭代器遍历
         * 格式是:for(集合中元素类型  元素别名 :  集合实例)
         */
        for (Integer n:arrayList
             ) {
            System.out.print(n+" ");

        }

        System.out.println();
//        /**
//         * 删除指定的元素对象o
//         * boolean remove(Object o)
//         * 返回的是Boolean类型
//         */
//        boolean remove1 = arrayList.remove(Integer.valueOf(23));
//        System.out.print("删除数据1:"+ remove1);
//        System.out.println();
//        /**
//         * 删除指定位置index(下标位置)的元素
//         * E remove(int index)
//         * 返回的是元素类型,将删除位置的元素返回
//         */
//        Integer remove = arrayList.remove(1);
//        System.out.print("删除的数据:"+ remove);
//
//        System.out.println("-----");
//        for (Integer a:arrayList
//                ) {
//            System.out.print(a+" ");
//
//        }
//        System.out.println("-----");
//
       ArrayList<Integer> list1 =  new ArrayList<>();
       list1.add(45);
       list1.add(2);
       list1.add(78);
       list1.add(56);
        for (Integer n:list1
                ) {
            System.out.print(n+" ");

        }
        System.out.println();
        System.out.println("----");
        /**
         *arrayList:23 45 55 78
         * list1:45 2 78 56
         * 保存当前集合中共有的数据进行数据保存(求两集合的交集)
         * boolean retainAll(Collection<?> c)
         */
//        boolean a =arrayList.retainAll(list1);
//        System.out.println(a);

        /**
         * 获取当前集合元素个数
         * int size()
         */
        int size = arrayList.size();
        System.out.println(size);
        
        
        for (Integer n:arrayList
                ) {
            System.out.print(n+" ");

        }

练习:

/**
         * 并集:获取两个集合中所有元素
         * 交集:获取两个集合中相同的元素
         * 差集:a与b的差集,即我有你没有的
         */

        ArrayList <Integer> a = new ArrayList <Integer>();
        a.add(1);
        a.add(2);
        a.add(3);

        ArrayList <Integer> b = new ArrayList <Integer>();
        b.add(3);
        b.add(4);
        b.add(5);

        /**
         * 并集:1 2 3 4 5
         * 交集:3
         * (a与b)差集:1 2
         */
        
        //并集
        a.addAll(b);
        
        //交集
        a.retainAll(b);
        
        //差集
        a.removeAll(b);

ArrayList工作原理及实现

特点、需要通过源码底层实现查看实现逻辑
①ArrayList集合的使用及特点:
**特点:**1、元素存放和插入顺序一致
2、数据是可以重复的
3、可以存储null
4、底层数据结构是数组
5、可以动态扩容的,默认容量是10
6、扩容是按照原大小的1.5倍进行扩容
构造函数

 //无参构造
        ArrayList<Integer> list = new ArrayList<Integer>();
        //通过指定集合容量大小来实例化
        ArrayList<Integer> list1 = new ArrayList<>(100);
        //通过Collection集合实例来实例化一个集合
        ArrayList<Integer> list2 = new ArrayList<>(list);

通过JDK源码来研究ArrayList的实现
1.关注继承关系
2.属性和默认值
3.构造函数
4.扩容机制、扩容时机
5.底层数据结构(数组、链表、队列、栈、哈希表…)
6.常见方法实现原理(add,remove,get…)

ArrayList:
继承关系:

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable

继承自AbstractList,AbstractList是一个抽象类,是实现了List接口,他是一个数组队列,提供了相关的添加、删除、修改、遍历等基本功能实现,方法子类对方法复用,如果子类有特殊功能可以重写父类的方法;

ArrayList实现了List接口,list接口继承自collection接口,在collection接口提供的方法基础上,有一些新的方法提供,比如get、set、add等特有的方法;

ArrayList实现了RandomAccess接口,即提供了随机访问功能,为list提供快速访问的功能;

ArrayList实现了Cloneable接口,即包含了函数clone(),能被克隆;

ArrayList实现了Serializable接口,意味着ArrayList支持序列化去传输(IO).

属性和默认值:

//默认初始容量是10
    private static final int DEFAULT_CAPACITY = 10;
//空数组实例
    private static final Object[] EMPTY_ELEMENTDATA = {};
//存储数据使用的是数组,数组存储的数据类型是Object
   private transient Object[] elementData; 
//用来记录存放数据的个数
    private int size;

ArrayList底层存储元素是使用数组
数组 elementData.length: 表示当前数组容量,最大存储的数据个数
*size:*实际存放的数据个数

构造函数:

//有参构造函数:通过指定初始容量initialCapacity来实例化ArrayList
public ArrayList(int initialCapacity) {
        super();
        //参数校验
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity);
        //实例化一个大小为initialCapacity数组并将数组赋值给elementData
        this.elementData = new Object[initialCapacity];
    }

//无参构造函数
    public ArrayList() {
        super();
        //给定空的数组
        this.elementData = EMPTY_ELEMENTDATA;
        //将默认值的赋值在add中完成
    }


   //通过集合实例来实例化ArrayList
    public ArrayList(Collection<? extends E> c) {
    //将集合转化为数组,直接赋值给 elementData
        elementData = c.toArray();
        //将集合中已有元素的大小赋值给size
        size = elementData.length;
        // c.toArray might (incorrectly) not return Object[] (see 6260652)
        if (elementData.getClass() != Object[].class)
            //完成数据拷贝
            elementData = Arrays.copyOf(elementData, size, Object[].class);
    }

常见方法源码解析:
add:添加元素

    public boolean add(E e) {
    //考虑扩容
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        //将新增元素插入elementData数组尾部,并对size+1
        elementData[size++] = e;
        return true;
    }
    private void ensureCapacityInternal(int minCapacity) {
        //当数组为空时,获取当前容量值
        if (elementData == EMPTY_ELEMENTDATA) {
            //在添加第一个元素时,当无参构造的实例时,第一次会进入该if方法
            //在未指定集合容量时,默认情况下数组初始化大小为10
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }

        ensureExplicitCapacity(minCapacity);
    }
 private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

        //数据空间不足,考虑扩容 
        if (minCapacity > elementData.length )
            grow(minCapacity);
    }
//扩容点
private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
       //扩容大小  oldCapacity >> 1 => oldCapacity/2    即1.5倍
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        //扩容范围的限制
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        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);
    }

    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }

    modCount是版本控制器,也是ArrayList中的属性(继承自AbstractList中的属性),和业务无关,仅仅是做版本控制,在集合进行变更(增删改)时会自增1
    扩容机制和扩容时机:当要插入数据的个数大于数组容量,需要扩容,按照原数组大小的1.5倍扩容,需要将原集合数据拷贝到新数组中
add过程:
       1、如果存储数组为空,获取默认的大小值是10
       2、如果需要大小超过数组大小、考虑扩容,按照原数组大小的1.5倍扩容
       3、通过创建新数组,将元素组大小拷贝到新数组中
       4、将新增元素插入最后的size位置并对size进行加1操作


get:获取元素

 public E get(int index) {
       //检查查询位置的合法性 index < size
        rangeCheck(index);

        return elementData(index);
    }
    private void rangeCheck(int index) {
        if (index >= size)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }

 E elementData(int index) {
        return (E) elementData[index];
    }

remove:删除元素

 public boolean remove(Object o) {
 //删除操作判断区分是否为null值,如果为null,判断相等使用== 如果不为null,判断相等用equals
        if (o == null) {
            //元素为空时
            for (int index = 0; index < size; index++)
                if (elementData[index] == null) {
                    fastRemove(index);
                    return true;
                }
        } else {
            //不为空 
            for (int index = 0; index < size; index++)
                if (o.equals(elementData[index])) {
                    fastRemove(index);
                    return true;
                }
        }
        return false;
    }
    //将index后续的数据前移一位
 private void fastRemove(int index) {
        modCount++;
        int numMoved = size - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
 //Arrays.copyof()拷贝和System.arraycopy拷贝
 //将最后一个位置置为null,并将size-1
        elementData[--size] = null; // clear to let GC do its work
    }

Arrays.copyof()拷贝和System.arraycopy拷贝:
1、使用 Arrays.copyOf() 方法对数组进行拷贝时,不需要目标数组的信息,只需要源数组和拷贝数据的长度信息,返回的新数组的长度也就是拷贝数据的长度;

2、使用 System.arraycopy() 方法对数组进行拷贝时,需要目标数组的信息,同时需要原始数组、原始数组的拷贝位置,目标数组的拷贝位置和拷贝长度信息;

3Arrays.copyOf() 底层也有调用 System.arraycopy()
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值