【JavaSE-07】:集合(1):Collection接口(含源码分析)

一、概述

  • 数组在内存存储方面的特点:
  1. 数组一旦初始化以后,长度就确定了。
  2. 数组声明的类型,就决定了进行元素初始化时的类型,保存和操作的必须为同一类型的元素。
  3. 数组中提供的方法非常有限,对于添加、删除、插入数据等操作,非常不便,同时效率不高。
  4. 获取数组中实际元素的个数的需求,数组没有现成的属性或方法可用。
  5. 数组存储数据的特点:有序、可重复。对于无序、不可重复的需求,不能满足。
  • 集合:
  1. 可以动态保存任意多个对象,使用比较方便;
  2. 提供了一系列方便的操作对象的方法:如add、remove、set、get等;
  3. 使用集合添加、删除元素的代码更简洁。

Java 集合可分为 Collection 和 Map 两种体系
1.单列集合:
在这里插入图片描述
2.双列集合:
在这里插入图片描述

二、Collection接口和常用方法

1. Collection常用方法

常用方法 方法名
1、添加 add(Object obj)
addAll(Collection coll)
2、获取有效元素的个数 int size()
3、清空集合 void clear()
4、是否是空集合 boolean isEmpty()
5、是否包含某个元素 boolean contains(Object obj):是通过元素的equals方法来判断是否是同一个对象;
boolean containsAll(Collection c):也是调用元素的equals方法来比较的。拿两个集合的元素挨个比较。
6、删除 boolean remove(Object obj) :通过元素的equals方法判断是否是要删除的那个元素。只会删除找到的第一个元素
boolean removeAll(Collection coll):取当前集合的差集
7、取两个集合的交集 boolean retainAll(Collection c):把交集的结果存在当前集合中,不 影响c
8、集合是否相等 boolean equals(Object obj)
9、转成对象数组 Object[ ] toArray()
10、获取集合对象的哈希值 hashCode()
11、遍历 iterator():返回迭代器对象,用于集合遍历

2. Collection接口遍历元素的方式1——使用Iterator(迭代器)

   Collection接口继承了java.lang.Iterable接口,该接口有一个iterator()方法,所有实现了Collection接口的集合类都有一个iterator()方法,用以返回一个实现了 Iterator 接口的对象。
   Iterator 仅用于遍历集合,Iterator 本身并不提供承装对象的能力。如果需要创建 Iterator 对象,则必须有一个被迭代的集合。

Iterator iterator = coll.iterator();
        while (iterator.hasNext()) {
   
            Object obj =  iterator.next();
            System.out.println(obj);
        }

在这里插入图片描述
注意:在调用 iterator.next() 方法之前必须要调用 iterator.hasNext()进行检测。若不调用,且下一条记录无效,直接调用 iterator.next()会抛出NoSuchElementException异常。
● 在调用循环结束后,iterator迭代器指向最后一个元素,再次使用 iterator.next( ) 方法会报错。

Iterator iterator = coll.iterator();
        while (iterator.hasNext()) {
   
            Object obj =  iterator.next();
            System.out.println(obj);
        }
        iterator.next();//报异常:java.util.NoSuchElementException

如果希望再次遍历,Collection集合需要重新调用 iterator() 获取一个新的迭代器对象,重置迭代器,集合对象每次调用 iterator() 方法都得到一个全新的迭代器对象,默认游标都在集合的第一个元素之前。

Iterator iterator = coll.iterator();
        while (iterator.hasNext()) {
   
            Object obj =  iterator.next();
            if(obj.equals("Tom")){
    
                  iterator.remove(); 
                  }
        }

注意:

  1. Iterator可以删除集合的元素,但是是遍历过程中通过迭代器对象的 remove 方法,不是集合对象的 remove 方法。
  2. 如果还未调用 next() 或在上一次调用 next 方法之后已经调用了 remove 方法, 再调用 remove 都会报异常 IllegalStateException。

3. Collection接口遍历元素的方式2——增强型循环for

  • 遍历操作不需获取Collection或数组的长度,无需使用索引访问元素。
  • 遍历集合的底层调用Iterator完成操作。可以理解为简化版的 iterator 迭代器遍历。
  • 它也可以用来遍历数组。
    在这里插入图片描述

三、 Collection子接口之一:List接口

由于数组的一些局限性,常采用List替代数组。
● List集合类中元素有序、且可重复,集合中的每个元素都有其对应的顺序索引。
● List容器中的元素都对应一个整数型的序号记载其在容器中的位置,可以根据序号存取容器中的元素。
● JDK API中List接口的实现类常用的有:ArrayList、LinkedList 和 Vector。

1. List接口方法

List除了从Collection集合继承的方法外,List 集合里添加了一些根据索引来操作集合元素的方法。

序号 方法
1 void add(int index, Object ele):在index位置插入ele元素
2 boolean addAll(int index, Collection eles):从index位置开始将eles中的所有元素添加进来
3 Object get(int index):获取指定index位置的元素
4 int indexOf(Object obj):返回obj在集合中首次出现的位置
5 int lastIndexOf(Object obj):返回obj在当前集合中末次出现的位置
6 Object remove(int index):移除指定index位置的元素,并返回此元素
7 Object set(int index, Object ele):设置指定index位置的元素为ele
8 List subList(int fromIndex, int toIndex):返回从fromIndex到toIndex 位置的子集合

2. List实现类之一:ArrayList

● ArrayList 是 List 接口的典型实现类、主要实现类
● 本质上,ArrayList是对象引用的一个"变长"数组

ArrayList的底层操作机制源码分析:重点
扩容机制:

  1. ArrayList中维护了一个Object类型的数组elementData
transient Object[] elementData;// transient  表示瞬间,短暂的,表示该属性不会被序列化
  1. 当创建ArrayList对象时,如果使用的是无参构造器,则初始 elementData 容量为0,在第1次添加元素时,则扩容 elementData 为10,如此后需要再次扩容,则扩容 elementData 为1.5倍。
  2. 如果使用的是指定大小的有参构造器,则初始elementData的容量为指定大小,如果需要扩容,则直接扩容为elementData的1.5倍。
private int size;
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = new Object[0];
//ArrayList的无参构造器
public ArrayList() {
   
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; //创建了一个空的elementData数组
    }

//ArrayList的有参构造器
public ArrayList(Collection<? extends E> c) {
   
        this.elementData = c.toArray();
        if ((this.size = this.elementData.length) != 0) {
   
            if (this.elementData.getClass() != Object[].class) {
   
                this.elementData = Arrays.copyOf(this.elementData, this.size, Object[].class);
            }
        } else {
   
            this.elementData = EMPTY_ELEMENTDATA;
        }

    }

第1次添加元素时:

    public boolean add(E e) {
   
        ++this.modCount;
        this.add(e, this.elementData, this.size);// 初始默认值 this.size:0
        return true;
    }
    
    private void add(E e, Object[] elementData, int s) {
   
        if (s == elementData.length) {
   
            elementData = this.grow();  
        }

        elementData[s] = e; //先确定是否需要扩容,再赋值
        this.size = s + 1;
    }

● 初始状态时,elementData长度默认为0的空数组;
● 第一次赋值时,先使用modCount 来记录集合被修改的次数;
然后调用add方法:
1)先判断是否需要扩容(元素数量等于数组长度);需要扩容则调用 grow() 方法扩容,第一次扩容后新数组长度为 10,第二次及之后扩容为为旧数组的1.5倍;
判断规则:
若第一次赋值的元素数量少于10,( minCapacity=元素个数+1<=10),利用扩容机制,设置新数组长度为10;
若第一次赋值的元素数量大于10,( minCapacity=元素个数+1>10),利用扩容机制,设置新数组长度为当前添加元素的数量长度;
2)再利用copeof()方法拷贝原来的数据,再赋值
● 第二次及之后赋值时,先记录修改次数,然后调用add方法:
先判断是否需要扩容;
1)不需要扩容时,直接赋值;
2)需要扩容则调用grow()方法扩容,扩容为为旧数组的1.5倍;再拷贝原来的数组元素,再赋值。
(此处有检查最大容量的判断)
扩容机制实现源码:

    private Object[] grow() {
   
        return this.grow(this.size + 1);
    }
    private Object[] grow(int minCapacity) {
   
        return this.elementData = Arrays.copyOf(this.elementData, this<
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值