ArrayList类中的属性
public class ArrayList<E> extends AbstractList<E>implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{@java.io.Serialprivate static final long serialVersionUID = 8683452581122892189L;/*** DEFAULT_CAPACITY表示集合默认的初始容量*/private static final int DEFAULT_CAPACITY = 10;/*** 空数组EMPTY_ELEMENTDATA,在使用有参构造方法时传递0进去,创建ArrayList集合时就会使用这个数组*/private static final Object[] EMPTY_ELEMENTDATA = {};/**默认容量的空数组DEFAULTCAPACITY_EMPTY_ELEMENTDATA*/private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};/*** 集合中真实存储元素的数组elementData*/transient Object[] elementData; // non-private to simplify nested class access/*** 集合中元素的个数* @serial*/private int size; //int类型的成员变量初始值为0
ArrayList类中的构造方法
-
无参构造方法:相当于内部创建了一个空的数组
/*** Constructs an empty list with an initial capacity of ten.*/public ArrayList() {//将成员变量中的 默认容量的空数组 赋值给 真实存储元素的数组//this.elementData = {}this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;}
-
有参构造方法分析:内部创建了一个指定长度的数组 并赋值给了elementData
main方法:
public class Test {public static void main(String[] args) {ArrayList list = new ArrayList(20); //创建一个指定初始容量为20的ArrayList集合}
}
-
有参构造方法源码:
public ArrayList(int initialCapacity) { // initialCapacity=20if (initialCapacity > 0) {//内部创建了一个长度为20的数组,并赋值给this.elementDatathis.elementData = new Object[initialCapacity]; } else if (initialCapacity == 0) {//如果传递的是0,就将空数组EMPTY_ELEMENTDATA 赋值给 this.elementDatathis.elementData = EMPTY_ELEMENTDATA;} else {//如果在构造方法中传递负数,就会抛出如下异常throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity);}}
无参构造方法创建的对象:添加方法
第一次添加数据:
在main方法中:
import java.util.ArrayList;public class Test {public static void main(String[] args) {ArrayList list1 = new ArrayList();list1.add(1); //添加第一个元素进去}
}
第一次添加数据的流程:
-
一级一级的调用下去
public boolean add(E e) {//确定内部数组的容量 0 + 1ensureCapacityInternal(size + 1); // Increments modCount!!//将要添加的元素 添加 到数组中有数据的下一个位置elementData[size++] = e; return true;}-------------------------------------------------------------------------------------//minCapacity:是ArrayList集合需要的最小容量(暂时这样理解)private void ensureCapacityInternal(int minCapacity) { // minCapacity=1if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { // {}=={}// 10 1minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);}//通过得到的minCapacity去确定数组的长度ensureExplicitCapacity(minCapacity);}-------------------------------------------------------------------------------------private void ensureExplicitCapacity(int minCapacity) { //minCapacity=10modCount++; //记录对当前集合操作的次数// 集合需要的最小容量minCapacity 大于 elementData数组的长度时就会扩容(也就是当集合内部的数组不够存储元素时才会扩容) 10-0if (minCapacity - elementData.length > 0)//扩容grow(minCapacity);}-------------------------------------------------------------------------------------private void grow(int minCapacity) { //minCapacity=10int oldCapacity = this.elementData.length; //原来的数组长度为0int newCapacity = oldCapacity + (oldCapacity >> 1); //新的容量0if (newCapacity - minCapacity < 0) { //0 - 10 < 0,执行newCapacity = minCapacity; //newCapacity = 10 }if (newCapacity - 2147483639 > 0) { //10 - 21亿 < 0newCapacity = hugeCapacity(minCapacity);}//将空数组{} 复制到 一个长度为 10的新数组中,然后将新的数组赋值给elementData。此时size还是0this.elementData = Arrays.copyOf(this.elementData, newCapacity);}//然后回去继续向下执行,执行的就是向数组中添加数据的操作public boolean add(E e) {//确定内部数组的容量 0 + 1ensureCapacityInternal(size + 1); // 0 + 1//将要添加的元素 添加 到数组中有数据的下一个位置elementData[size++] = e; //elementData={e,,,,,,,,,} 数组的length=10,size=1return true;}
第二次添加元素:
-
第二次添加元素也还不会扩容
main方法中:
package string.demo;import java.util.ArrayList;public class Test {public static void main(String[] args) {ArrayList list1 = new ArrayList();list1.add(1);list1.add(2); //第二次添加数据}
}
第二次添加元素的执行流程:
public boolean add(E e) {//确定内部数组的容量 1 + 1 = 2ensureCapacityInternal(size + 1); // Increments modCount!!//将要添加的元素 添加 到数组中有数据的下一个位置elementData[size++] = e; return true;}-------------------------------------------------------------------------------------private void ensureCapacityInternal(int minCapacity) { // minCapacity=2if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { // {1,,,...}!={} 不执行语句体minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);}//确定数组的容量ensureExplicitCapacity(minCapacity);}-------------------------------------------------------------------------------------private void ensureExplicitCapacity(int minCapacity) { minCapacity=2modCount++; //记录对当前集合操作的次数 modCount=modCount + 1 (modCount=2)// 集合需要的最小容量minCapacity 大于 elementData数组的长度时就会扩容 2 - 10 < 0:不执行if语句体,也就是不扩容if (minCapacity - elementData.length > 0)//扩容grow(minCapacity);}
-----------------------------------------------------------------------------------------//然后回去继续向下执行,执行的就是向数组中添加数据的操作public boolean add(E e) {//确定内部的容量 0 + 1ensureCapacityInternal(size + 1); // Increments modCount!!//将要添加的元素 添加 到数组中有数据的下一个位置elementData[size++] = e; // {1,2,.....} 此时:数组length = 10,元素个size=2return true;}
第十一次添加元素
-
此时ArrayList集合内部的数组不够存储新元素了,会扩容
public boolean add(E e) {//此时elementData数组:{1,2,3,4,5,6,7,8,9,10} size = 10 , length = 10ensureCapacityInternal(size + 1); // 10 + 1 =11//将要添加的元素 添加 到数组中有数据的下一个位置elementData[size++] = e; return true;}-------------------------------------------------------------------------------------private void ensureCapacityInternal(int minCapacity) { minCapacity = 11if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);}//确定数组的容量ensureExplicitCapacity(minCapacity); //11}-------------------------------------------------------------------------------------private void ensureExplicitCapacity(int minCapacity) { minCapacity=11modCount++; //记录对当前集合操作的次数 modCount=modCount + 1 (modCount=11)// minCapacity 大于 elementData数组的长度时就会扩容 11-10 > 0:扩容if (minCapacity - elementData.length > 0)//扩容grow(minCapacity);}-------------------------------------------------------------------------------------private void grow(int minCapacity) { //minCapacity=11//oldCapacity = 10int oldCapacity = this.elementData.length; //获取原容量的长度//新的容量newCapacity是在原容量的基础上扩容1.5倍//newCapacity = 10 + 5int newCapacity = oldCapacity + (oldCapacity >> 1); if (newCapacity - minCapacity < 0) { //15 - 11 > 0,不执行newCapacity = minCapacity; }if (newCapacity - 2147483639 > 0) { //15 - 21亿 < 0,不执行newCapacity = hugeCapacity(minCapacity);}//将{1,2,3,4,5,6,7,8,9,10}长度为10的数组 复制到 长度为 15的新数组中,然后将新的数组赋值给elementData。this.elementData = Arrays.copyOf(this.elementData, newCapacity);}//再回去执行向数组中添加元素的逻辑public boolean add(E e) {//此时elementData数组:{1,2,3,4,5,6,7,8,9,10} size = 10 , length = 10ensureCapacityInternal(size + 1); // 10 + 1 =11//将要添加的元素 添加 到数组中有数据的下一个位置{1,2,3,4,5,6,7,8,9,10,11,,,,} 此时size=11 length=15elementData[size++] = e; return true;}
有参构造方法创建的对象:添加方法
执行时调用的方法都和无参的一样
main方法:
package string.demo;import java.util.ArrayList;public class Test {public static void main(String[] args) {//elementData = {,,,,,} 长度为20的数组ArrayList list2 = new ArrayList(20);list2.add(1);}
}
添加数据:
public boolean add(E e) {//确定内部的容量 0 + 1ensureCapacityInternal(size + 1); // Increments modCount!!//将要添加的元素 添加 到数组中有数据的下一个位置elementData[size++] = e; return true;}-------------------------------------------------------------------------------------private void ensureCapacityInternal(int minCapacity) { // minCapacity=1if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { // elementData != {}不执行minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);}//确定数组的容量ensureExplicitCapacity(minCapacity);}-------------------------------------------------------------------------------------private void ensureExplicitCapacity(int minCapacity) { //minCapacity=1modCount++; //记录对当前集合操作的次数// 集合中的元素个数 等于数组的长度时才会扩容 if (minCapacity - elementData.length > 0) //1 - 20 < 0 不扩容//扩容grow(minCapacity);}-------------------------------------------------------------------------------------private void grow(int minCapacity) { int oldCapacity = this.elementData.length; int newCapacity = oldCapacity + (oldCapacity >> 1); //新的容量if (newCapacity - minCapacity < 0) { newCapacity = minCapacity; }if (newCapacity - 2147483639 > 0) { newCapacity = hugeCapacity(minCapacity);}this.elementData = Arrays.copyOf(this.elementData, newCapacity);}
ArrayList中的get方法
main方法:
package string.demo;import java.util.ArrayList;public class Test {public static void main(String[] args) {ArrayList list1 = new ArrayList();list1.add(1);list1.add(2);list1.get(0);}
}
ArrayList中的get方法源码:
public E get(int index) {//检查下标是否合法Objects.checkIndex(index, size);//通过下标获取数组中对应的元素return elementData(index);}
ArrayList中的set方法
main方法:
package string.demo;import java.util.ArrayList;public class Test {public static void main(String[] args) {ArrayList list1 = new ArrayList();list1.add(1);list1.add(2);list1.set(1,"aaa");}
}
ArrayList中的set方法源码:
jdk17:
public E set(int index, E element) {Objects.checkIndex(index, size); //检查下标是否合法E oldValue = elementData(index); //获取原来下标对应的元素elementData[index] = element; //将新的元素赋值给数组中对应的下标位置上return oldValue; //返回原来的值}
过去版本的jdk:
public E set(int index, E element) {rangeCheck(index); //检查下标是否合法E oldValue = elementData(index); //获取原来下标对应的元素elementData[index] = element; //将新的元素赋值给数组中对应的下标位置上return oldValue; //返回原来的值}
ArrayList中的remove方法:
main方法:
package string.demo;import java.util.ArrayList;public class Test {public static void main(String[] args) {ArrayList list1 = new ArrayList();list1.add(1);list1.add(2);list1.add(3);list1.add(4);list1.add(5);list1.add(6);list1.add(7);list1.add(8);list1.add(9);list1.remove(3);}
}
ArrayList中的remove方法源码:
过去版本的jdk:
public E remove(int index) { index=3rangeCheck(index); //检查下标modCount++; //记录修改当前集合的次数E oldValue = elementData(index); //获取原来下标上的元素//计算要移动的元素的个数{1,2,3,4,5,6,7,8,9} //{1,2,3,5,6,7,8,9,null}int numMoved = size - index - 1; //9 - 3 - 1 = 5if (numMoved > 0)System.arraycopy(elementData //原数组, index+1 //开始移动的下标 5,6,7,8,9, elementData //目标数组, index, //开始的下标numMoved //要移动的元素个数);//{1,2,3,5,6,7,8,9,null} elementData[--size] = null; // clear to let GC do its workreturn oldValue;}
public E remove(int index) {Objects.checkIndex(index, size);final Object[] es = elementData;@SuppressWarnings("unchecked") E oldValue = (E) es[index];fastRemove(es, index);return oldValue;}
TreeSet的实现原理
在构造方法中创建了一个TreeMap实例
public TreeSet() {this(new TreeMap<>());}
在调用add方法时,本质上是调用了TreeMap的put方法
public boolean add(E e) {return m.put(e, PRESENT)==null;}
Hashset的实现原理
在其无参构造方法中实例化了一个HashMap实例
public HashSet() {map = new HashMap<>();}
在调用add方法的时候本质上是调用了HashMap的put方法
public boolean add(E e) {return map.put(e, PRESENT)==null;}
去除ArrayList集合中重复的元素
方式一:
会创建一个新的ArrayList集合
package collection;import java.util.ArrayList;public class ListTest {public static void main(String[] args) {ArrayList list1 = new ArrayList();list1.add(1);list1.add(3);list1.add(2);list1.add(null);list1.add("张三");list1.add("李四");list1.add(3);System.out.println(list1);//新创建一个List集合存储去重后的元素ArrayList list2 = new ArrayList();for (Object o : list1){ //遍历原来的集合if (!list2.contains(o)){ //判断新的集合中是否包含list1中的元素,如果没有则1添加到list2中list2.add(o);}}System.out.println(list2);}
}
运行结果:
[1, 3, 2, null, 张三, 李四, 3]
[1, 3, 2, null, 张三, 李四]
方式二
不创建新集合,使用选择排序的思想去除重复元素
package collection;import java.util.ArrayList;public class ListTest {public static void main(String[] args) {ArrayList list1 = new ArrayList();list1.add(1);list1.add(3);list1.add(2);list1.add(2);list1.add(2);list1.add("张三");list1.add("李四");list1.add(3);System.out.println(list1);for (int i = 0;i < list1.size() - 1;i++){for (int j = i + 1;j<list1.size();j++){if (list1.get(i).equals(list1.get(j))){list1.remove(j);j--;}}}System.out.println(list1);}
}