Detailed explanation of Java Collection framework | Collection system and core source code

Hi, welcome to JasperのBlog!

Collection system

Collection system considerations

  • List interface: orderly (the order of adding is consistent with the order of traversal), subscript and repeatable elements.
  • Set interface: unordered (the order of adding and traversal are inconsistent), no subscript, and elements cannot be repeated.

Collection parent interface

Collection method

Collection case implementation

public class CollectionTest {
    public static void main(String[] args) {
        Collection collection=new ArrayList();
        System.out.println("-----isEmpty------");
        //isEmpty determines whether the collection has elements. It returns true but not false
        System.out.println(collection.isEmpty());

        System.out.println("-----add------");
        //add adds an element to the collection
        Student s1=new Student("Zhang San",18);
        Student s2=new Student("Li Si",19);
        Student s3=new Student("Wang Wu",20);
        Student s4=new Student("Sun Liu",21);
        Student s5=new Student("Zhao Qi",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 returns the number of elements in the collection
        System.out.println(collection.size());

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

        System.out.println("------removeAll-----");
        //colletion.removeAll(Collection C)
        //Delete all elements that are also included in C from the collection
        Student s6=new Student("Liu Ba",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)
        //Only those elements in the collection that are also contained in C are retained
        //True is returned when there is no intersection, true is returned when there is intersection but not all intersection, and false is returned when two sets are equal
        Student s7=new Student("Lin Jiu",24);
        Collection collection3=new ArrayList();
        collection3.add(s7);
        collection3.add(s1);
        collection3.add(s2);
        System.out.println(collection);
        System.out.println("Intersection:"+collection.retainAll(collection3));
        Collection none=new ArrayList();
        Collection test=new ArrayList();
        test.addAll(collection);
        System.out.println("No intersection:"+test.retainAll(none));
        test.addAll(collection);
        System.out.println("Two sets are equal:"+test.retainAll(test));

        System.out.println("------contains-----");
        //Whether contains contains this element returns true, not false
        System.out.println(collection.contains(s2));
        //If conrtains (new object), it is equivalent to opening up a new space, which is different from the original s2
        System.out.println(collection.contains(new Student("Li Si",19)));

        System.out.println("------containsAll-----");
        //colletion.containsAll(Collection C)
        //If the collection contains T, all elements return true, otherwise return false
        Collection collection4=new ArrayList();
        collection4.add(s1);
        System.out.println(collection.containsAll(collection4));

        System.out.println("------equals and hashcode-----");
        //equals determines whether the addresses of each element of two sets are equal
        System.out.println(collection);
        Collection collection5=new ArrayList();
        collection5.add(s1);
        collection5.add(new Student("Li Si",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)
        //Add all elements in C to colletion
        collection.addAll(collection2);
        System.out.println(collection);

        System.out.println("------ergodic-----");
        //1. Enhance for traversal
        for (Object o : collection) {
            Student stu=(Student) o;
            System.out.printf("%s ",stu.getName());
        }
        System.out.printf("\n");
        //2. Iterator traversal
        Iterator it=collection.iterator();
        while (it.hasNext()){
            Student student = (Student) it.next();
            System.out.printf("%s ",student.getName());
            if (student.getName().equals("Liu Ba")){
                it.remove();
            }
        }
        System.out.printf("\n");
        System.out.println(collection);

        System.out.println("------toArray-----");
        //toArray() turns a collection into an array
        //toArray(T []) changes the collection to the specified T array
        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 clear collection elements
        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 +
                '}';
    }
}
//Output results:
-----isEmpty------
true
-----add------
[Student{name='Zhang San', age=18}, Student{name='Li Si', age=19}, Student{name='Wang Wu', age=20}, Student{name='Sun Liu', age=21}, Student{name='Zhao Qi', age=22}]
-----size------
5
-----remove------
[Student{name='Zhang San', age=18}, Student{name='Li Si', age=19}, Student{name='Sun Liu', age=21}, Student{name='Zhao Qi', age=22}]
------removeAll-----
[Student{name='Zhang San', age=18}, Student{name='Li Si', age=19}, Student{name='Zhao Qi', age=22}]
------retainAll-----
[Student{name='Zhang San', age=18}, Student{name='Li Si', age=19}, Student{name='Zhao Qi', age=22}]
Intersection: true
 No intersection: true
 Two sets are equal: false
------contains-----
true
false
------containsAll-----
true
------equals and hashcode-----
[Student{name='Zhang San', age=18}, Student{name='Li Si', age=19}]
collection-1492222893
collection5-1698792011
collection6-1492222893
false
true
------addAll-----
[Student{name='Zhang San', age=18}, Student{name='Li Si', age=19}, Student{name='Sun Liu', age=21}, Student{name='Liu Ba', age=23}]
------ergodic-----
Zhang San Li Si sun Liu Ba 
Zhang San Li Si sun Liu Ba 
[Student{name='Zhang San', age=18}, Student{name='Li Si', age=19}, Student{name='Sun Liu', age=21}]
------toArray-----
Zhang San, Li Si, sun Liu 
------clear-----
[Student{name='Zhang San', age=18}, Student{name='Li Si', age=19}, Student{name='Sun Liu', age=21}]
0

It is worth noting that the equals method of the Collection is not overridden

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("Apple","red");
        c1.add(apple);
        Collection c2=new ArrayList();
        c2.add(new Fruit("Apple","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));//Returns true because the string comparison overrides the equals method
    }
}
//Output results:
------Collection(obj)-------
false
1554874533 | 1846274167
------Collection(String)-------
true

List interface

List method

List case implementation

public class ListTest {
    public static void main(String[] args) {
        List list= new ArrayList();
        list.add(20);//Adding a base type automatically boxing
        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("-----ergodic-----");
        //1. Enhanced for 2 The iterator iterator inherits the Collection, and the two methods are the same
        //3.for loop
        for (int i=0;i<list.size();i++){
            System.out.printf("%d ",list.get(i));
        }
        System.out.println();
        //4. Using the list iterator, unlike the iterator, listIterator can traverse forward or backward, add, delete and modify elements
        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());
        }
    }
}
//Output results:
[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
-----ergodic-----
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 implementation class

ArrayList method and case implementation

public class ArrayListTest {
    public static void main(String[] args) {
        ArrayList arr=new ArrayList();
        Fruit apple=new Fruit("Apple","red");
        Fruit banana=new Fruit("Banana","yellow");
        Fruit orange=new Fruit("orange","orange");
        arr.add(apple);
        arr.add(banana);
        arr.add(orange);
        System.out.println("------The collection contains references to objects-------");
        apple.setName("Big apple");
        System.out.println("Add to the collection and then change apple Name of");
        System.out.println(arr);
        //The method of adding elements is the same as that of List, which will not be repeated here
        System.out.println("------remove(obj)-------");
        //In the source code of remove element, the equals method is actually called. Mainly compare the addresses of the two
        //If you override Fruit's equals method, you will compare the contents of the two
        arr.remove(new Fruit("orange","orange"));
        System.out.println(arr);
        System.out.println("------ergodic-------");
        //1. Enhanced for 2 Iterator iterator 3 Listiterator list iterator 4 for
        //In the reverse order of the list, first move the pointer to the tail, and then traverse from the tail to the head
        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("Banana","yellow")));
        System.out.println("------indexOf(obj)-------");
        System.out.println(arr.indexOf(new Fruit("Banana","yellow")));

    }
}
//Output results:
------The collection contains references to objects-------
Add to the collection and then change apple Name of
[Fruit{name='Big apple', color='red'}, Fruit{name='Banana', color='yellow'}, Fruit{name='orange', color='orange'}]
------remove(obj)-------
[Fruit{name='Big apple', color='red'}, Fruit{name='Banana', color='yellow'}]
------ergodic-------
Fruit{name='Banana', color='yellow'} Fruit{name='Big apple', color='red'} 
------contains(obj)-------
true
------indexOf(obj)-------
1

Data structure of ArrayList

  • When analyzing a class, the data structure is often its soul. Understanding the underlying data structure actually understands the implementation idea of the class, and then analyze the specific implementation details. The underlying data structure of ArrayList is array. The array element type is Object type, which can store all types of data. All our operations on instances of the ArrayList class are based on arrays.

Source code analysis of ArrayList (JDK1.8)

Inheritance structure and hierarchy

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

Why inherit AbstractList first and let AbstractList implement List first? Instead of having ArrayList implement List directly?

  • Here is an idea that all interfaces are abstract methods, and abstract classes can have abstract methods and specific implementation methods. This is used to make AbstractList implement some general methods in the interface, and specific classes, such as ArrayList, inherit this AbstractList class and get some general methods, Then you are implementing some of your own unique methods. In this way, you can make the code more concise, extract the general methods in the classes at the bottom of the inheritance structure, and implement them together first to reduce repeated code. Therefore, it is generally seen that there is an abstract class above a class, which should be used for this purpose.

What interfaces does ArrayList implement

  • List interface: some people explained it for the convenience of looking up the code.
  • RandomAccess interface: it is used for fast random access. For efficiency problems, if the interface is implemented, the ordinary for loop is used to traverse, and the performance is higher.
  • Cloneable interface: after implementing this interface, you can use object Clone() method.
  • Serializable interface:
  • Implement the serialization interface, indicating that the class can be serialized. What is serialization? In short, it can change from class to byte stream transmission, and then from byte to original class.

Properties in class

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

    /**
     * Default initial capacity
     * Default initial capacity. 
     */
    private static final int DEFAULT_CAPACITY = 10;

    /**
     * Empty object array
     * Shared empty array instance used for empty instances.
     */
    private static final Object[] EMPTY_ELEMENTDATA = {};

    /**
     * Initial object array
     * 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 = {};

    /**
     * Element array
     * 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

    /**
     * The actual element size is 0 by default
     * The size of the ArrayList (the number of elements it contains).
     * @serial
     */
    private int size;
}

Construction method

Parameterless construction ArrayList()

//Constructs an empty list with an initial capacity of ten.
//Construct an empty list with an initial capacity of 10
public ArrayList() {
  	this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

Parametrically structured ArrayList(int initialCapacity)

//Constructs an empty list with the specified initial capacity.
//Construct an empty list and customize the initial capacity
public ArrayList(int initialCapacity) {
    if (initialCapacity > 0) {
      	//Customize initial capacity size
        this.elementData = new Object[initialCapacity];
    } else if (initialCapacity == 0) {
        //Equivalent to parameterless construction method
        this.elementData = EMPTY_ELEMENTDATA;
    } else {
        throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity);
    }
}

ArrayList with parameters (collection <? Extensions E > C)

//Constructs a list containing the elements of the specified collection, in the order they are returned by the collection's iterator.
//Constructs a list containing the elements of the specified collection in the order in which the collection iterator returns the elements
public ArrayList(Collection<? extends E> c) {
    elementData = c.toArray();
  	//The implementation method of toarray() of each collection is different, so you need to judge if it is not object [] Class type, you need to use the methods in ArrayList to transform it for so long.
    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.
        //Equivalent to parameterless construction method
        this.elementData = EMPTY_ELEMENTDATA;
    }
}

Source code analysis of add method

boolean add(E)

Case 1 parameterless initialization and adding an element
/*
		ArrayList arr = new ArrayList(); //This sentence can be understood as initializing an empty array
		arr.add(xxx);
*/

//Appends the specified element to the end of this list.
//Add a specific element to the end of the list
public boolean add(E e) {
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    elementData[size++] = e;
    return true;
}

/*
		Enter the function ensureCapacityInternal(size + 1); 
		size Is the number of data in the array. Because you want to add an element, size+1
*/
private void ensureCapacityInternal(int minCapacity) {
  	ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}

/*
		Enter the function calculateCapacity(elementData, minCapacity);
	  Where elementData is still an empty array, minCapacity = value of initial size + 1 = 1
*/
private static int calculateCapacity(Object[] elementData, int minCapacity) {
  	/*
  			Note: if both a and b are arrays, then:
            a=b ,The comparison is the address
            a.equals(b) The comparison is the address
            Arrays.equals(a, b) The element content is compared
        When comparing two strings, it uses the equals() method under the String class, which compares the object value.
				When comparing the values of two Arrays, you need to use the equals() method in the Arrays class. That is, Arrays equals(a, b)
  	*/
  	//In the constructor, this elementData = DEFAULTCAPACITY_ EMPTY_ ELEMENTDATA;
  	//So the if statement executes true math Max (10, 1) = 10 returns 10
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
      return Math.max(DEFAULT_CAPACITY, minCapacity);
    }
    return minCapacity;
}
/*
		Enter the function ensureCapacityInternal(int minCapacity); minCapacity=10
	  But note that the size of this elementData has not been really changed
*/
private void ensureExplicitCapacity(int minCapacity) {
    modCount++;
    // overflow-conscious code
  	// minCapacity=10 elementData.length=0, so mincapacity - elementdata length > 0
    if (minCapacity - elementData.length > 0)
      grow(minCapacity);
}
/*
		Enter the function grow(minCapacity); minCapacity=10, which is the core function of array expansion
*/
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 execute the following if statement
    if (newCapacity - minCapacity < 0)
      newCapacity = minCapacity; //newCapacity=10
  	//If the newCapacity exceeds the maximum capacity limit, call hugeCapacity, that is, give the maximum value that can be given to newCapacity
    if (newCapacity - MAX_ARRAY_SIZE > 0)
      newCapacity = hugeCapacity(minCapacity);
    //minCapacity is usually close to size, so this is a win:
  	//After the new capacity has been determined, change the capacity of the copy array
    elementData = Arrays.copyOf(elementData, newCapacity);
}
/*
		If newCapacity exceeds the maximum capacity limit, hugeCapacity is called
*/
private static int hugeCapacity(int minCapacity) {
    if (minCapacity < 0) // overflow
      throw new OutOfMemoryError();
  	//If minCapacity is greater than MAX_ARRAY_SIZE, then integer MAX_ Value returns, otherwise MAX_ARRAY_SIZE return
    return (minCapacity > MAX_ARRAY_SIZE) ?
      Integer.MAX_VALUE :
    MAX_ARRAY_SIZE;
}
/*
		Finally, go back and execute Boolean add (E)
*/
public boolean add(E e) {
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    elementData[size++] = e;
    return true;
}
Case 2 has parameters to initialize and add an element
/*
		ArrayList arr = new ArrayList(6); //The size of elementData is 6
		arr.add(xxx);
*/
private static int calculateCapacity(Object[] elementData, int minCapacity) {
  	//When this step is executed, the if statement does not hold and returns 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, so the grow th function will not be executed and the capacity will not be expanded
    if (minCapacity - elementData.length > 0)
      grow(minCapacity);
}
Case 3 when no meal is initialized and the 11th element is added
/*
		ArrayList arr = new ArrayList(); //This sentence can be understood as initializing an empty array
		arr.add(xxx);
		:
		:
		arr.add(xxx);
		arr.add(xxx); 10 elements have been added. When you want to add the 11th element
		
		When the 10th element is added, execute elementData[size++] = e; It means elementData[size] = e, and then the size increases by 10
*/
private static int calculateCapacity(Object[] elementData, int minCapacity) {
  	//When this step is executed, the if statement does not hold and returns 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, so the grow th function will be executed to expand the capacity
    if (minCapacity - elementData.length > 0)
      grow(minCapacity);
}
private void grow(int minCapacity) {
    // overflow-conscious code
    int oldCapacity = elementData.length; //oldCapacity=10
  	//Oldcapacity > > 1 indicates that the arithmetic is shifted to the right by 1 bit
    //For example, the binary of 10 is 01010, the arithmetic is shifted by 1 bit to the right, and 00101 is converted to hexadecimal 5
    int newCapacity = oldCapacity + (oldCapacity >> 1); //newCapacity= 10 + 5 = 15
    //newCapacity - minCapacity = 15 - 11 >0
    if (newCapacity - minCapacity < 0)
      newCapacity = minCapacity; 
  	//If the newCapacity exceeds the maximum capacity limit, call hugeCapacity, that is, give the maximum value that can be given to newCapacity
    if (newCapacity - MAX_ARRAY_SIZE > 0)
      newCapacity = hugeCapacity(minCapacity);
    //minCapacity is usually close to size, so this is a win:
  	//After the new capacity has been determined, change the capacity of the copy array
    elementData = Arrays.copyOf(elementData, newCapacity);
}
public boolean add(E e) {
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    elementData[size++] = e; //Execute this line of code after capacity expansion
    return true;
}

void add(int,E)

public void add(int index, E element) {
    //Check whether the index, that is, the insertion position is reasonable.
    rangeCheckForAdd(index);
    ensureCapacityInternal(size + 1);  // Increments modCount!!
  	//Copy elementData from the element beginning with index to elementData, and copy from index + 1. The copy length is size - index
    System.arraycopy(elementData, index, elementData, index + 1,
                     size - index);
    elementData[index] = element;
    size++;
}

//rangeCheckForAdd(int index)
private void rangeCheckForAdd(int index) {
  	//The insertion position must not be greater than size and less than 0
    if (index > size || index < 0)
      //If so, report this cross-border exception
      throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
//void arraycopy
public static native void arraycopy(Object src,  int  srcPos, Object dest, int destPos, int length);

Source code analysis of remove method

remove(int)

public E remove(int index) {
    //Check the rationality of the index
    rangeCheck(index);
    modCount++;
    E oldValue = elementData(index);//Find the element directly by index
    int numMoved = size - index - 1;//Calculate the number of digits to move
    if (numMoved > 0)
      	//Use system Arraycopy move copy element
        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) {
  	//Obviously, arrayList can store null values
    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])) {
              	//The internal of the fastRemove(index) method is almost the same as the implementation of remove(index)
                fastRemove(index);
                return true;
            }
    }
    return false;
}

removeAll(collection c)

public boolean removeAll(Collection<?> c) {
    Objects.requireNonNull(c);
    return batchRemove(c, false);
}
//batchRemove is the core method of removeAll. It is used in two places. If the complexity is false, it is used for removeAll; If true, it is used for retainAll(). retainAll() is used to detect whether two sets have an intersection.
private boolean batchRemove(Collection<?> c, boolean complement) {
      final Object[] elementData = this.elementData;
      int r = 0, w = 0;//r is used to control the loop. w is the number of intersections of records. r and w can be regarded as two pointers to move between arrays
      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.
        //Usually, if the program executes normally, r==size at last, if r= Size description: exceptions are reported during the use of the contains method
        if (r != size) {
          //The elements before r have been completed. Copy the start position of the r pointer of elementData to the start position of the w pointer of elementData, and copy the size - r length
          System.arraycopy(elementData, r,
                           elementData, w,
                           size - r);
          w += size - r; //w pointer moves size - r units
        }
        //retainAll(): true is returned if there is no intersection, and true is returned if there is intersection but not all intersection. false is returned if the two sets are equal. Therefore, it is impossible to confirm whether there is intersection between the two sets according to the return value
        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;
}

Other methods

set(int,E)

public E set(int index, E element) {
  	//Check whether the index is legal
    rangeCheck(index);
		//Find the old value
    E oldValue = elementData(index);
  	//Assign new value
    elementData[index] = element;
  	//Return old value
    return oldValue;
}

indexOf(Object)

//Find whether the specified element exists in the array from the beginning
public int indexOf(Object o) {
    if (o == null) {
      // Traverse the array, find the first empty element, and return the subscript
      for (int i = 0; i < size; i++)
        if (elementData[i]==null)
          return i;
    } else {
      // Traverse the array, find the first element equal to the specified element, and return the subscript
        for (int i = 0; i < size; i++)
          if (o.equals(elementData[i]))
            return i;
   }
   return -1;
}

get(int) method

public E get(int index) {
  	//Check whether the index is legal
    rangeCheck(index);
		//Returns the element value corresponding to the index
    return elementData(index);
}

Keywords: Java Back-end JavaSE

Added by bassdog65 on Thu, 09 Dec 2021 18:45:22 +0200