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

Java集合框架体系结构:深入解析Collection与Map两大体系 Java集合框架是Java语言中用于数据存储和处理的核心库,提供了统一的架构。本文详细解析了Collection和Map两大根接口及其实现类的继承关系、特点和使用场景。Collection接口包括List、Set和Queue三个子接口,分别用于有序集合、无序集合和队列操作。List的实现类如ArrayList、LinkedList和Vector在底层实现、线程安全、随机访问和插入删除等方面各有特点。Set的实现类如HashSet、TreeSet和LinkedHashSet则在排序方式、时间复杂度和允许nul 阅读详情

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

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!

集合框架源码分析 java集合- 集合框架源码分析 立即下载

相关推荐

超实用!VS Code配置C/C++开发环境全攻略

本文提供了一份详细的VS Code配置C/C++开发环境全攻略。从MinGW-w64编译器的选择与安装,到VS Code核心扩展的配置,再到tasks.json构建任务与launch.json调试环境的设置,手把手指导初学者完成从环境搭建到高效开发与调试的全过程,帮助开发者快速上手C/C++项目。

weixin_28829479的博客 185

Java源码解析-重点集合框架篇

本文讲解了重点的集合框架,从源码的层面和数据结构的层面进行了详细分析,通过本文的学习,希望大家对集合框架有一个细致的了解。接下来我会更新常用的并发容器,结合多线程的知识进行分析。

郝老三~~~~~~~~~~~~~ 1622

【tensorrt】——深入解析TypeError: pybind11::init()报错:CUDA版本冲突与解决方案

本文深入解析了TensorRT中常见的TypeError: pybind11::init()报错问题,重点探讨了CUDA版本冲突的根源与解决方案。通过实际案例展示了PyTorch与TensorRT的版本兼容性问题诊断方法,并提供了conda环境管理、环境变量配置等实用修复技巧,帮助开发者有效解决CUDA初始化失败问题。

ggg99的专栏 272

【Java从0到1学习】12 Java集合框架源码解读(6w字长文,快来收藏)

本文主要针对常见的集合进行源码分析,让大家更好的掌握集合的知识

笑小枫 806

10位PWM能否满足电梯±5mm平层精度?4位扩展法让10位PWM达到14位精度

电梯平层精度直接关系乘坐舒适性与安全性,而PWM分辨率是决定精度的关键因素之一。10位PWM能否满足±5mm的平层精度要求?本文从分辨率与物理量的对应关系出发,结合工程精度需求与实战对比,给出明确的选型结论与解决方案,请参考优快云博客《4位扩展法:基于ATtiny816的高精度PWM软件扩展方法》和《低成本高精度PWM:4位扩展法原理、实现和工程实践》。10位PWM的分辨率为 $2^{10} = 1024$ 级。

m0_73354873的博客 244

MultiOTP Credential Provider避坑指南:从安装到RDP双因素认证的全流程解析

本文详细解析了MultiOTP Credential Provider从安装到实现RDP双因素认证(MFA)的全流程,重点分享了Docker部署、Active Directory集成及网络级认证(NLA)兼容性等环节的实战避坑经验,旨在帮助运维人员高效、稳定地部署离线双因素认证方案,提升Windows远程桌面安全性。

weixin_29255731的博客 642

(二十一)Java集合框架源码深度解析

Java集合框架是Java语言中最重要、最常用的API之一。通过深入理解其源码实现,我们可以:更高效地使用集合类根据场景选择最合适的实现避免常见的陷阱和性能问题编写更健壮、更高效的代码从设计角度看,集合框架体现了多种优秀的设计原则和模式:接口与实现分离算法与数据结构分离迭代器模式策略模式模板方法模式随着Java版本的演进,集合框架也在不断优化和改进,如Java 8引入的Stream API和Lambda表达式使集合操作更加简洁和强大。

MeyrlNotFound的博客 1134

基于STM32L4XX、HAL库的MCP4561数字电位器驱动程序设计

/ HAL库需要左移一位。* @param address: 设备地址(0x2C-0x2F)* @param hmcp: MCP4561句柄。* @param hmcp: MCP4561句柄。* @param hmcp: MCP4561句柄。* @param hmcp: MCP4561句柄。* @param hmcp: MCP4561句柄。* @param hmcp: MCP4561句柄。* @param hmcp: MCP4561句柄。* @param hi2c: I2C句柄。

zhusl6688的博客 340

Java集合框架全解析:从Collection到List,附源码剖析

本文摘要: Java集合框架主要介绍了Collection和List两大接口及其实现类。Collection是单例集合顶层接口,包含add、remove等基本操作,遍历方式包括迭代器、增强for和lambda表达式。List接口扩展了有序、可重复集合特性,提供索引操作和五种遍历方式。重点分析了ArrayList(数组实现,查询快)和LinkedList(链表实现,增删快)的底层实现及源码,包括ArrayList的1.5倍扩容机制和LinkedList的双向链表结构。文章还对比了数组与集合的区别,并详细讲解了

sxjaaa的博客 875

SAM3 LoRA Fine-Tuning|SAM3微调(完全对齐官方训练和配置)

本文介绍了基于官方SAM3模型使用LoRA技术进行图像目标检测与分割微调的项目。项目完全对齐官方训练配置,支持多类别高效微调,且不影响原模型的开放词汇提示能力。微调后模型在航拍图像中对道路、车辆等目标的分割效果显著提升,误检率降低。 项目提供完整的训练和推理流程: 支持双卡并行训练,显存需求大(完整微调需30G+显存) 提供训练脚本和配置文件,可灵活调整参数 包含推理可视化工具,支持与原模型效果对比,内置训练结果分析工具,可生成指标对比图 数据集采用COCO格式。

weixin_46248968的博客 359

Linux内核驱动模型--PCIe(PCI Express)驱动​​

本文系统介绍了Linux内核中PCIe驱动的设计与实现。首先从架构定位入手,指出PCIe驱动基于PCI子系统扩展支持高速、低功耗特性。核心数据结构struct pci_driver包含设备匹配表id_table、生命周期函数probe/remove等关键组件。文章详细解析了驱动与设备的绑定流程、资源管理机制,并重点阐述了MSI-X中断、电源管理、热插拔和多队列等高级特性实现方案。最后提供了lspci、dmesg等调试工具的使用方法,总结了PCIe驱动在支持高性能设备中的关键作用。全文通过架构设计、核心结构、

amy_mhd的博客 428

深入解析:Java 集合框架与源码分析

Java 集合框架由多个接口和类组成,提供了一种存储和操作对象的标准方式。主要接口包括CollectionListSet和Map。所有集合类都实现了这些接口,以便于数据的管理。Java 集合框架提供了丰富的集合类型,开发者应根据实际需求选择合适的集合。理解集合的内部实现和性能特性将有助于写出高效的代码。通过对ArrayListHashSet和HashMap的深入分析,我们可以看到这些集合是如何运作的,以及它们的优势和局限性。希望通过本篇文章,能够帮助你深入理解 Java 集合框架,从而在开发中游刃有余!

一名热衷于技术的全栈开发者,专注于前端与后端的全面技术探索。在这里,我将分享我在技术领域的学习与成长,助力更多开发者的进步。 1281

以太网_RGMII接口与GMII接口的转化_03

RGMII接口转GMII接口!

weixin_42499230的博客 378

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

注:详解核心源码 = 逐句解释源码 + 分情况举例说明 + 必要辅助图解 目录Vector实现类Vector方法及案例实现Vector的源码分析(JDk1.8)继承结构和层次关系类中的属性构造方法无参构造 Vector()有参构造 Vector(int initialCapacity)有参构造 Vector(int initialCapacity, int capacityIncrement)有参构造 Vector(Collection<? extends E> c)add方法的源码分析ad.

Jasper的博客 579

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

Java集合框架解析:从基础到底层源码

单线程环境快速查询:ArrayList/HashMap频繁增删:LinkedList需要排序:TreeSet/TreeMap高并发场景读多写少:CopyOnWriteArrayList写多读少:ConcurrentHashMap严格一致性:Collections.synchronized系列函数式编程使用Stream API进行链式处理优先选择不可变集合(Guava/Java9+)彩蛋知识点。

Hello World!你好世界! 2866

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

Java集合框架学习总结(含源码分析)

Java集合框架Java集合框架概述 Java集合框架概述 用作自己学习笔记:如有不当的地方,还请指点~ 首先上图啦:看看Java集合相关类的关系图

渣渣飞的博客 1143

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

Java基础--------集合框架

一. 概念 集合:通常情况下,把具有某种相同性质的一类东西,汇聚成的集体,称为集合。比如,用Java编程的所有程序员,全体中国人等。在数学中的定义是,由一个或多个确定的元素所构成的整体叫做集合。 Java中的集合:是一种...

詹煜彪9527 1万+

详解Java中的Collection单列集合(从底层到用法超详细解析和细节分析)

在 Java 中,集合框架是开发过程中最常用的数据结构之一,其中 Collection 接口是整个集合框架的基础。Collection 是处理单列数据的接口,它定义了一些通用的操作,允许对一组对象进行操作。今天我们将深入介绍 Java 中的单列集合 Collection 接口,以及它的常见子接口和实现类。

q251932440的博客 1643

Java集合:Collection接口

Collection是一个接口,继承自Iterable。我们先看一下Iterable接口的源码 一、Iterable package java.lang; import java.util.Iterator; import java.util.Objects; import java.util.Spliterator; import java.util.Spliterators; import java.util.function.Consumer; /** *实现这个接口的的类允许使

栗筝i的博客 3418

Java集合框架的基础:Collection接口、Iterator迭代器详解

系统解析Java集合框架的Collection接口、迭代器Iterator的工作原理与使用、增强for循环等遍历方式,帮助初学者深入理解并正确使用集合。

qq_17862337的博客 1002

JAVA基础核心-集合(上)-collection集合体系

什么是集合,collection集合的体系JCF及集合的实例化应用一.集合1.什么是集合2.泛型3.lambda表达式二.collection集合的体系图三.collection集合体系的实例化应用1.List集合1.1List集合-动态数组ArrayList1.2List集合-链表实现LinkedList1.3List集合-栈实现stack2.队列queue2.1Deque双向队列3.set集合 一.集合 1.什么是集合 1.Java集合类存放在java.util包中,是一个用来存放对象的容器(集合可以存

m0_56688298的博客 1195

javaSE集合框架(一)—— Collection接口

javaSE集合框架

qq_44886213的博客 1579

Collection集合框架

Collection集合框架集合框架接口集合框架主要继承链 集合框架接口 在研究源码的时候,许多人会用面向过程的思路去分析源码。这是一种比较不好的习惯,因此,笔者强调,研究对象时,要多采用“面向对象”的思想。即“继承(接口)决定方法,结构决定算法”,从而在看源码时,能够以“物以类聚”的观点,一叶知秋。 图1 集合接口 图1是官网上JDK8提供的视图,值得注意的是,虽然Map接口不继承于Coll...

彬 1032

Java集合框架(Collection Framework)学习笔记

集合框架是Java中用于存储和操作一组对象的统一架构,它提供了:一系列接口(定义行为)多个实现类(具体数据结构)各种算法(排序、查找等)集合类添加删除查找备注ArrayListO(1)摊销O(n)O(1)动态数组LinkedListO(1)O(1)O(n)双向链表HashSetO(1)O(1)O(1)哈希表TreeSetO(log n)O(log n)O(log n)红黑树HashMapO(1)O(1)O(1)哈希表TreeMap。

weixin_52528537的博客 1966

【java集合一】根接口Collection、Map

Java集合类是一种非常实用的工具类,主要用于保存、盛装其它数据(集合里只能保存对象),因此集合类也被成为容器类。所有的集合类都位于java.util包下,在java.util.concurrent下还提供了一些支持多线程的集合类。Java的集合类主要由两个接口派生而来:Collection和Map,这两个是Java集合框架的根接口。 1.Collection接口 Collection派生出三个子接口,Set代表不可重复的无序集合、List代表可重复的有序集合、Queue是java提供的队列

Cherie 2823

集合:Collection详解.

一、集合概述 1.1、什么是集合?有什么用 数组其实就是一个集合。集合实际上就是一个容器。可以来容纳其它类型的数据。 集合为什么说在开发中使用较多?集合是一个容器,是一个载体,可以一次容纳多个对象。 在实际开发中,假设连接数据库,数据库当中有10条记录, 那么假设把这10条记录查询出来,在java程序中会将10条 数据封装成10个java对象,然后将10个java对象放到某一个 集合当中,将集合传到前端,然后遍历集合,将一个数据一个 数据展现出来。 ...

lwj_07的博客 3383
上一篇: Java知识梳理04|String内存分析(JDK1.8)
下一篇: Java集合框架|Collection体系和核心源码详解(二)
I'm Jasper
博客等级 码龄8年 4粉丝 26原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值