Java集合框架|Collection体系和核心源码详解(一)

注:详解核心源码 = 逐句解释源码 + 分情况举例说明 + 必要辅助图解

Collection体系

Collection体系 注意事项

  • List接口:有序(指添加的顺序和遍历的顺序是一致的)、有下标、元素可重复。
  • Set接口:无序(指添加的顺序和遍历的顺序是不一致的)、无下标、元素不能重复。

Collection父接口

Collection方法

Collection案例实现

public class CollectionTest {
    public static void main(String[] args) {
        Collection collection=new ArrayList();
        System.out.println("-----isEmpty------");
        //isEmpty 判断集合是否有元素,有返回true,没有返回false
        System.out.println(collection.isEmpty());

        System.out.println("-----add------");
        //add 往集合中添加元素
        Student s1=new Student("张三",18);
        Student s2=new Student("李四",19);
        Student s3=new Student("王五",20);
        Student s4=new Student("孙六",21);
        Student s5=new Student("赵七",22);
        collection.add(s1);
        collection.add(s2);
        collection.add(s3);
        collection.add(s4);
        collection.add(s5);
        System.out.println(collection);

        System.out.println("-----size------");
        //size 返回集合中元素个数
        System.out.println(collection.size());

        System.out.println("-----remove------");
        collection.remove(s3);
        System.out.println(collection);

        System.out.println("------removeAll-----");
        //colletion.removeAll(Collection C)
        //从collection中删除那些也包含在C中的所有元素
        Student s6=new Student("刘八",23);
        Collection collection2=new ArrayList();
        collection2.add(s4);
        collection2.add(s6);
        collection.removeAll(collection2);
        System.out.println(collection);

        System.out.println("------retainAll-----");
        //colletion.retainAll(Collection C)
        //仅保留collection中那些也包含在C的元素
        //没有一个交集返回true,有交集但不全交也返回true,而两个集合相等的时候,返回false
        Student s7=new Student("林九",24);
        Collection collection3=new ArrayList();
        collection3.add(s7);
        collection3.add(s1);
        collection3.add(s2);
        System.out.println(collection);
        System.out.println("有交集:"+collection.retainAll(collection3));
        Collection none=new ArrayList();
        Collection test=new ArrayList();
        test.addAll(collection);
        System.out.println("没有交集:"+test.retainAll(none));
        test.addAll(collection);
        System.out.println("两个集合相等:"+test.retainAll(test));

        System.out.println("------contains-----");
        //contains 是否包含该元素 是返回true 不是返回false
        System.out.println(collection.contains(s2));
        //如果conrtains(新的对象) 那么就相当于开辟了新的空间,与原来的s2不同
        System.out.println(collection.contains(new Student("李四",19)));

        System.out.println("------containsAll-----");
        //colletion.containsAll(Collection C)
        //若collection包含T所有元素返回true,反之返回false
        Collection collection4=new ArrayList();
        collection4.add(s1);
        System.out.println(collection.containsAll(collection4));

        System.out.println("------equals and hashcode-----");
        //equals 判断两个集合的每个元素的地址是否相等
        System.out.println(collection);
        Collection collection5=new ArrayList();
        collection5.add(s1);
        collection5.add(new Student("李四",19));
        Collection collection6=new ArrayList();
        collection6.add(s1);
        collection6.add(s2);
        System.out.println("collection"+collection.hashCode());
        System.out.println("collection5"+collection5.hashCode());
        System.out.println("collection6"+collection6.hashCode());
        System.out.println(collection.equals(collection5));
        System.out.println(collection.equals(collection6));

        System.out.println("------addAll-----");
        //colletion.addAll(Collection C)
        //colletion中添加C中所有元素
        collection.addAll(collection2);
        System.out.println(collection);

        System.out.println("------遍历-----");
        //1.增强for遍历
        for (Object o : collection) {
            Student stu=(Student) o;
            System.out.printf("%s ",stu.getName());
        }
        System.out.printf("\n");
        //2.迭代器遍历
        Iterator it=collection.iterator();
        while (it.hasNext()){
            Student student = (Student) it.next();
            System.out.printf("%s ",student.getName());
            if (student.getName().equals("刘八")){
                it.remove();
            }
        }
        System.out.printf("\n");
        System.out.println(collection);

        System.out.println("------toArray-----");
        //toArray() 将集合变为数组
        //toArray(T []) 将集合变为指定T数组
        Student[] t=new Student[5];
        Student[] arr = (Student[]) collection.toArray(t);
        for (Student student : arr) {
            if (student!=null){
                System.out.printf("%s ",student.getName());
            }
        }
        System.out.printf("\n");

        System.out.println("------clear-----");
        //clear清空集合元素
        System.out.println(collection);
        collection.clear();
        System.out.println(collection.size());
    }
}
class Student{
    private String name;
    private int age;

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
//输出结果:
-----isEmpty------
true
-----add------
[Student{name='张三', age=18}, Student{name='李四', age=19}, Student{name='王五', age=20}, Student{name='孙六', age=21}, Student{name='赵七', age=22}]
-----size------
5
-----remove------
[Student{name='张三', age=18}, Student{name='李四', age=19}, Student{name='孙六', age=21}, Student{name='赵七', age=22}]
------removeAll-----
[Student{name='张三', age=18}, Student{name='李四', age=19}, Student{name='赵七', age=22}]
------retainAll-----
[Student{name='张三', age=18}, Student{name='李四', age=19}, Student{name='赵七', age=22}]
有交集:true
没有交集:true
两个集合相等:false
------contains-----
true
false
------containsAll-----
true
------equals and hashcode-----
[Student{name='张三', age=18}, Student{name='李四', age=19}]
collection-1492222893
collection5-1698792011
collection6-1492222893
false
true
------addAll-----
[Student{name='张三', age=18}, Student{name='李四', age=19}, Student{name='孙六', age=21}, Student{name='刘八', age=23}]
------遍历-----
张三 李四 孙六 刘八 
张三 李四 孙六 刘八 
[Student{name='张三', age=18}, Student{name='李四', age=19}, Student{name='孙六', age=21}]
------toArray-----
张三 李四 孙六 
------clear-----
[Student{name='张三', age=18}, Student{name='李四', age=19}, Student{name='孙六', age=21}]
0

值得注意:Collection的equals方法并没有重写

class Fruit{
    private String name;
    private String color;

    public Fruit(String name, String color) {
        this.name = name;
        this.color = color;
    }
}
public class ArrayListTest {
    public static void main(String[] args) {
        System.out.println("------Collection-------");
        Collection c1=new ArrayList();
        Fruit apple=new Fruit("苹果","red");
        c1.add(apple);
        Collection c2=new ArrayList();
        c2.add(new Fruit("苹果","red"));
        System.out.println(c1.equals(c2));
        System.out.println(c1.hashCode()+" | "+c2.hashCode());
        System.out.println("------Collection(String)-------");
        Collection c3=new ArrayList();
        Collection c4=new ArrayList();
        c3.add(new String("Hello"));
        c4.add(new String("Hello"));
        System.out.println(c3.equals(c4));//返回true,因为字符串的比较重写了equals方法
    }
}
//输出结果:
------Collection(obj)-------
false
1554874533 | 1846274167
------Collection(String)-------
true

List接口

List方法

List案例实现

public class ListTest {
    public static void main(String[] args) {
        List list= new ArrayList();
        list.add(20);//添加基本类型会自动装箱
        list.add(40);
        list.add(50);
        System.out.println(list);
        System.out.println("-----add(int,E)-----");
        list.add(1,60);
        System.out.println(list);

        System.out.println("-----addAll(int,E)-----");
        List list2= new ArrayList();
        list2.add(20);
        list2.add(80);
        list.addAll(2,list2);
        System.out.println(list);

        System.out.println("-----remove(int)-----");
        list.remove(2);
        System.out.println(list);

        System.out.println("-----get(int)-----");
        System.out.println(list.get(2));

        System.out.println("-----set(int,E)-----");
        list.set(1,50);
        System.out.println(list);

        System.out.println("-----lastIndexOf/indexOf(Object)-----");
        System.out.println(list.indexOf(50));
        System.out.println(list.lastIndexOf(50));

        System.out.println("-----遍历-----");
        //1.增强for 2.iterator迭代器 继承Collection,这两个方法遍历一样
        //3.for循环
        for (int i=0;i<list.size();i++){
            System.out.printf("%d ",list.get(i));
        }
        System.out.println();
        //4.使用列表迭代器,和iterator的区别,listIterator可以向前或向后遍历添加删除修改元素
        ListIterator listIterator = list.listIterator();
        while (listIterator.hasNext()){
            System.out.printf("[%d]:%d ",listIterator.nextIndex(),listIterator.next());
        }
        System.out.println();
        while (listIterator.hasPrevious()){
            System.out.printf("[%d]:%d ",listIterator.previousIndex(),listIterator.previous());
        }
    }
}
//输出结果:
[20, 40, 50]
-----add(int,E)-----
[20, 60, 40, 50]
-----addAll(int,E)-----
[20, 60, 20, 80, 40, 50]
-----remove(int)-----
[20, 60, 80, 40, 50]
-----get(int)-----
80
-----set(int,E)-----
[20, 50, 80, 40, 50]
-----lastIndexOf/indexOf(Object)-----
1
4
-----遍历-----
20 50 80 40 50 
[0]:20 [1]:50 [2]:80 [3]:40 [4]:50 
[4]:50 [3]:40 [2]:80 [1]:50 [0]:20 

ArrayList实现类

ArrayList方法及案例实现

public class ArrayListTest {
    public static void main(String[] args) {
        ArrayList arr=new ArrayList();
        Fruit apple=new Fruit("苹果","red");
        Fruit banana=new Fruit("香蕉","yellow");
        Fruit orange=new Fruit("橙子","orange");
        arr.add(apple);
        arr.add(banana);
        arr.add(orange);
        System.out.println("------集合中存的是对象的引用-------");
        apple.setName("大苹果");
        System.out.println("添加进集合之后再改变apple的名字");
        System.out.println(arr);
        //添加元素 和List的方法一样,此处不再赘述
        System.out.println("------remove(obj)-------");
        //删除元素 remove源码中其实是调用了equals方法。主要是比较两者的地址
        //如果重写Fruit的equals方法之后,就是比较两者的内容了
        arr.remove(new Fruit("橙子","orange"));
        System.out.println(arr);
        System.out.println("------遍历-------");
        //1.增强for 2.iterator迭代器 3.listIterator列表迭代器 4.for
        //列表逆序 先将指针移动到尾部,然后从尾部向头部遍历
        ListIterator listIterator = arr.listIterator();
        while (listIterator.hasNext()){
            listIterator.next();
        }
        while(listIterator.hasPrevious()){
            Fruit f=(Fruit) listIterator.previous();
            System.out.printf("%s ",f.toString());
        }
        System.out.println();
        System.out.println("------contains(obj)-------");
        System.out.println(arr.contains(new Fruit("香蕉","yellow")));
        System.out.println("------indexOf(obj)-------");
        System.out.println(arr.indexOf(new Fruit("香蕉","yellow")));

    }
}
//输出结果:
------集合中存的是对象的引用-------
添加进集合之后再改变apple的名字
[Fruit{name='大苹果', color='red'}, Fruit{name='香蕉', color='yellow'}, Fruit{name='橙子', color='orange'}]
------remove(obj)-------
[Fruit{name='大苹果', color='red'}, Fruit{name='香蕉', color='yellow'}]
------遍历-------
Fruit{name='香蕉', color='yellow'} Fruit{name='大苹果', color='red'} 
------contains(obj)-------
true
------indexOf(obj)-------
1

ArrayList的数据结构

  • 分析一个类的时候,数据结构往往是它的灵魂所在,理解底层的数据结构其实就理解了该类的实现思路,具体的实现细节再具体分析。ArrayList底层的数据结构就是数组,数组元素类型为Object类型,即可以存放所有类型数据。我们对 ArrayList类的实例的所有的操作底层都是基于数组的。

ArrayList的源码分析(JDK1.8)

继承结构和层次关系

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
  ......
}
为什么要先继承AbstractList,而让AbstractList先实现List?而不是让ArrayList直接实现List?
  • 这里是有一个思想,接口中全都是抽象的方法,而抽象类中可以有抽象方法,还可以有具体的实现方 法,正是利用了这一点,让AbstractList是实现接口中一些通用的方法,而具体的类,如ArrayList就继承这个AbstractList类,拿到一些通用的方法,然后自己在实现一些自己特有的方法,这样一来,让代码更简洁,就继承结构最底层的类中通用的方法都抽取出来,先一起实现了,减少重复代码。所以一般看到 一个类上面还有一个抽象类,应该就是这个作用。
ArrayList实现了哪些接口
  • List接口:部分人解释是为了查阅代码方便。
  • RandomAccess接口:用来快速随机存取, 有关效率的问题,在实现了该接口的话,那么使用普通的for循环来遍历,性能更高。
  • Cloneable接口:实现了该接口,就可以使用Object.Clone()方法了。
  • Serializable接口:
  • 实现该序列化接口,表明该类可以被序列化,什么是序列化?简单的说,就是能够从类变成字节流传输,然后还能从字节流变成原来的类。

类中的属性

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
    /**
     * 版本号
     */
    private static final long serialVersionUID = 8683452581122892189L;

    /**
     * 默认初始容量
     * Default initial capacity. 
     */
    private static final int DEFAULT_CAPACITY = 10;

    /**
     * 空对象数组
     * Shared empty array instance used for empty instances.
     */
    private static final Object[] EMPTY_ELEMENTDATA = {};

    /**
     * 初始对象数组
     * Shared empty array instance used for default sized empty instances. We
     * distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
     * first element is added.
     */
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

    /**
     * 元素数组
     * The array buffer into which the elements of the ArrayList are stored.
     * The capacity of the ArrayList is the length of this array buffer. Any
     * empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
     * will be expanded to DEFAULT_CAPACITY when the first element is added.
     */
    transient Object[] elementData; // non-private to simplify nested class access

    /**
     * 实际元素大小,默认为0
     * The size of the ArrayList (the number of elements it contains).
     * @serial
     */
    private int size;
}

构造方法

无参构造 ArrayList()
//Constructs an empty list with an initial capacity of ten.
//构造一个空的列表,初始容量为10
public ArrayList() {
  	this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
有参构造 ArrayList(int initialCapacity)
//Constructs an empty list with the specified initial capacity.
//构造一个空的列表,自定义初始容量大小
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);
    }
}
有参构造 ArrayList(Collection<? extends E> c)
//Constructs a list containing the elements of the specified collection, in the order they are returned by the collection's iterator.
//按照集合迭代器返回元素的顺序构造包含指定集合的元素的列表
public ArrayList(Collection<? extends E> c) {
    elementData = c.toArray();
  	//每个集合的toarray()的实现方法不一样,所以需要判断一下,如果不是Object[].class类型,那么久需要使用ArrayList中的方法去改造一下。
    if ((size = elementData.length) != 0) {
        // c.toArray might (incorrectly) not return Object[] (see 6260652)
        if (elementData.getClass() != Object[].class)
            elementData = Arrays.copyOf(elementData, size, Object[].class);
    } else {
        // replace with empty array.
        //等同于无参构造方法
        this.elementData = EMPTY_ELEMENTDATA;
    }
}

add方法的源码分析

boolean add(E)
情况1 无参初始化并添加一个元素
/*
		ArrayList arr = new ArrayList(); //这句可以理解为初始化一个空的数组
		arr.add(xxx);
*/

//Appends the specified element to the end of this list.
//添加一个特定的元素到list的末尾
public boolean add(E e) {
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    elementData[size++] = e;
    return true;
}

/*
		进入这个函数ensureCapacityInternal(size + 1); 
		size是数组中数据的个数,因为要添加一个元素,所以size+1
*/
private void ensureCapacityInternal(int minCapacity) {
  	ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}

/*
		进入这个函数calculateCapacity(elementData, minCapacity);
	  其中elementData还是空的数组,minCapacity=初始size的值+1=1
*/
private static int calculateCapacity(Object[] elementData, int minCapacity) {
  	/*
  			注意:若a,b都为数组,则:
            a=b ,比较的是地址
            a.equals(b) 比较的是地址
            Arrays.equals(a, b) 比较的是元素内容
        当比较两个字符串的时候,它使用的是String类下的equals()方法,这个方法比较的是对象值。
				当比较两个数组的值的时候,需要使用Arrays类中的equals()方法。即Arrays.equals(a, b)
  	*/
  	//在构造函数中this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
  	//所以if语句执行true Math.max(10, 1)=10 返回10
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
      return Math.max(DEFAULT_CAPACITY, minCapacity);
    }
    return minCapacity;
}
/*
		进入这个函数ensureCapacityInternal(int minCapacity); 此时minCapacity=10
	  但注意还没有真正的改变这个elementData的大小
*/
private void ensureExplicitCapacity(int minCapacity) {
    modCount++;
    // overflow-conscious code
  	// minCapacity=10 elementData.length=0 所以minCapacity - elementData.length > 0
    if (minCapacity - elementData.length > 0)
      grow(minCapacity);
}
/*
		进入这个函数grow(minCapacity); minCapacity=10 这是数组扩容的核心函数
*/
private void grow(int minCapacity) {
    // overflow-conscious code
    int oldCapacity = elementData.length; //oldCapacity=0
    int newCapacity = oldCapacity + (oldCapacity >> 1); //newCapacity= 0 + 0 = 0
  	//newCapacity - minCapacity = -10 < 0执行下面if语句
    if (newCapacity - minCapacity < 0)
      newCapacity = minCapacity; //此时newCapacity=10
  	//如果newCapacity超过了最大的容量限制,就调用hugeCapacity,也就是将能给的最大值给 newCapacity
    if (newCapacity - MAX_ARRAY_SIZE > 0)
      newCapacity = hugeCapacity(minCapacity);
    //minCapacity is usually close to size, so this is a win:
  	//新的容量大小已经确定好了,就copy数组,改变容量大小
    elementData = Arrays.copyOf(elementData, newCapacity);
}
/*
		如果newCapacity超过了最大的容量限制,就调用hugeCapacity
*/
private static int hugeCapacity(int minCapacity) {
    if (minCapacity < 0) // overflow
      throw new OutOfMemoryError();
  	//如果minCapacity大于MAX_ARRAY_SIZE,那么就Integer.MAX_VALUE返回,反之将 MAX_ARRAY_SIZE返回
    return (minCapacity > MAX_ARRAY_SIZE) ?
      Integer.MAX_VALUE :
    MAX_ARRAY_SIZE;
}
/*
		最后再回过来执行boolean add(E e)
*/
public boolean add(E e) {
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    elementData[size++] = e;
    return true;
}
情况2 有参初始化并添加一个元素
/*
		ArrayList arr = new ArrayList(6); //这句可以理解为elementData的大小已经是6
		arr.add(xxx);
*/
private static int calculateCapacity(Object[] elementData, int minCapacity) {
  	//执行到这一步的时候 if语句不成立 返回minCapacity=size+1=1
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
      return Math.max(DEFAULT_CAPACITY, minCapacity);
    }
    return minCapacity;
}
private void ensureExplicitCapacity(int minCapacity) {
    modCount++;
    // overflow-conscious code
  	// minCapacity - elementData.length = 1 - 6 < 0 所以不会执行grow函数,也就不会扩容
    if (minCapacity - elementData.length > 0)
      grow(minCapacity);
}
情况3 无餐初始化并添加第11个元素时
/*
		ArrayList arr = new ArrayList(); //这句可以理解为初始化一个空的数组
		arr.add(xxx);
		:
		:
		arr.add(xxx);
		arr.add(xxx); 已经添加10个元素,要添加第11个元素时
		
		添加了第10个元素时,执行elementData[size++] = e; 意味着elementData[size] = e,然后size自增等于10
*/
private static int calculateCapacity(Object[] elementData, int minCapacity) {
  	//执行到这一步的时候 if语句不成立 返回minCapacity=size+1=11
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
      return Math.max(DEFAULT_CAPACITY, minCapacity);
    }
    return minCapacity;
}
private void ensureExplicitCapacity(int minCapacity) {
    modCount++;
    // overflow-conscious code
  	// minCapacity - elementData.length = 11 - 10 > 0 所以会执行grow函数,扩容
    if (minCapacity - elementData.length > 0)
      grow(minCapacity);
}
private void grow(int minCapacity) {
    // overflow-conscious code
    int oldCapacity = elementData.length; //oldCapacity=10
  	//oldCapacity >> 1表示算术右移1位
    //打个比方10的二进制是01010算术右移1位,得00101即转为10进制为5
    int newCapacity = oldCapacity + (oldCapacity >> 1); //newCapacity= 10 + 5 = 15
    //newCapacity - minCapacity = 15 - 11 >0
    if (newCapacity - minCapacity < 0)
      newCapacity = minCapacity; 
  	//如果newCapacity超过了最大的容量限制,就调用hugeCapacity,也就是将能给的最大值给 newCapacity
    if (newCapacity - MAX_ARRAY_SIZE > 0)
      newCapacity = hugeCapacity(minCapacity);
    //minCapacity is usually close to size, so this is a win:
  	//新的容量大小已经确定好了,就copy数组,改变容量大小
    elementData = Arrays.copyOf(elementData, newCapacity);
}
public boolean add(E e) {
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    elementData[size++] = e; //扩容完之后再执行这行代码
    return true;
}
void add(int,E)
public void add(int index, E element) {
    //检查index也就是插入的位置是否合理。
    rangeCheckForAdd(index);
    ensureCapacityInternal(size + 1);  // Increments modCount!!
  	//将elementData从index开始的元素复制到elementData上,从index + 1开始复制,复制长度为size - index
    System.arraycopy(elementData, index, elementData, index + 1,
                     size - index);
    elementData[index] = element;
    size++;
}

//rangeCheckForAdd(int index)
private void rangeCheckForAdd(int index) {
  	//插入的位置肯定不能大于size 和小于0
    if (index > size || index < 0)
      //如果是,就报这个越界异常
      throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
//void arraycopy
public static native void arraycopy(Object src,  int  srcPos, Object dest, int destPos, int length);

remove方法的源码分析

remove(int)
public E remove(int index) {
    //检查index的合理性
    rangeCheck(index);
    modCount++;
    E oldValue = elementData(index);//通过索引直接找到该元素
    int numMoved = size - index - 1;//计算要移动的位数
    if (numMoved > 0)
      	//使用System.arraycopy移动复制元素
        System.arraycopy(elementData, index+1, elementData, index,
                         numMoved);
    elementData[--size] = null; // clear to let GC do its work
    return oldValue;
}
remove(Object)
public boolean remove(Object o) {
  	//显然arrayList可以存储null值
    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)方法的内部跟remove(index)的实现几乎一样
                fastRemove(index);
                return true;
            }
    }
    return false;
}
removeAll(collection c)
public boolean removeAll(Collection<?> c) {
    Objects.requireNonNull(c);
    return batchRemove(c, false);
}
//batchRemove是removeAll的核心方法,用于两处地方,如果complement为false,则用于removeAll;如果为true,则用于 retainAll(),retainAll()是用来检测两个集合是否有交集的。
private boolean batchRemove(Collection<?> c, boolean complement) {
      final Object[] elementData = this.elementData;
      int r = 0, w = 0;//r用来控制循环,w是记录有多少个交集,可以r,w分别看成两个指针在数组之间移动
      boolean modified = false;
      try {
        for (; r < size; r++)
          if (c.contains(elementData[r]) == complement)
            elementData[w++] = elementData[r];
      } finally {
        // Preserve behavioral compatibility with AbstractCollection,
        // even if c.contains() throws.
        //通常情况下,如果程序正常执行,最后r==size,如果r!=size说明contains方法使用过程报异常
        if (r != size) {
          //r之前的元素都已经完成,将elementData的r指针开始的位置复制到elementData的w指针开始的位置,复制size - r长度
          System.arraycopy(elementData, r,
                           elementData, w,
                           size - r);
          w += size - r; //w指针移动size - r个单位
        }
        //retainAll():没有一个交集返回true,有交集但不全交也返回true,而两个集合 相等的时候,返回false,所以不能根据返回值来确认两个集合是否有交集
        if (w != size) {
          // clear to let GC do its work
          for (int i = w; i < size; i++)
            elementData[i] = null;
          modCount += size - w;
          size = w;
          modified = true;
        }
      }
      return modified;
}

其他方法

set(int,E)
public E set(int index, E element) {
  	//检验索引是否合法
    rangeCheck(index);
		//找出旧值
    E oldValue = elementData(index);
  	//赋新值
    elementData[index] = element;
  	//返回旧值
    return oldValue;
}
indexOf(Object)
//从首开始查找数组里面是否存在指定元素
public int indexOf(Object o) {
    if (o == null) {
      // 遍历数组,找到第一个为空的元素,返回下标
      for (int i = 0; i < size; i++)
        if (elementData[i]==null)
          return i;
    } else {
      // 遍历数组,找到第一个和指定元素相等的元素,返回下标
        for (int i = 0; i < size; i++)
          if (o.equals(elementData[i]))
            return i;
   }
   return -1;
}
get(int)方法
public E get(int index) {
  	//检验索引是否合法
    rangeCheck(index);
		//返回索引对应的元素值
    return elementData(index);
}

Hi, welcome to JasperのBlog

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值