目录
数组的缺点
集合
集合的框架
(单列集合) Collection接口和它的实现类
ArrayList类的介绍:
1、长度开始时必须指定,一旦指定,不能更改
2、保存的必须是同一数据类型的元素
3、对数组元素的增删改查(crud)操作比较麻烦
1、可以动态保存任意多个对象(类型可以不同) ,如果是基本数据类型会自动装包
2、集合含有许多方法,方便进行crud操作
图一:
图二:
分析:
1、集合主要主要是两组(单列集合[图一] 、双列集合[图二])
2、Collection 接口有两个重要的子接口 List Set , 他们的实现子类都是单列集合
3、Map 接口的实现子类 是双列集合,存放的K-V
Collection接口下又有两个接口继承了它,分别是List接口 和 Set接口
分析:
1、Collection接口的所有实现子类可以存放多个元素,每个元素都可以是Object
2、对于List接口的实现子类,可以存放重复的元素,而对于Set接口的实现子类,不允许存放重复元素
3、List接口的实现子类中的元素是有序的,而Set接口中的实现子类是无序的
对Collection集合作进一步说明
Collection接口形式:public interface Collection<E> extends Iterable<E>
说明:
1、 <E>是泛型,集合可以使用泛型向集合中传入一个参数(引用类型),来指定元素存储的类型,如果不传默认是Object
2、在创建对象时 可以使用泛型来限定元素的存储类型
3、集合存储的元素是引用类型(对象),如果存储基本数据类型,系统自动会包装成引用类型对象
具体实现:Collection是一个接口,所以只能通过实现子类来创建对象,这里以ArrayList来创建对象
public class Test { public static void main(String[] args) { /* Collection<E> c = new ArrayList<T>(); 在多态实现时,编译看左边,左边的泛型就会控制集合中元素的类型必须是 E 或者是E的子类 右边的泛型,是运行时类型其中的T必须和E一致 或者 是E的子类 一般形式:左边的泛型存在右边没有,或者右边的泛型存在左边没有 例如:Collection<String> c = new ArrayList<T>(); 要求 c这个集合中 只能添加String 类型的元素 通过add方法 添加元素 Collection<String> c = new ArrayList<>(); c.add("hello world"); c.add("!"); System.out.println(c); 结果是:[hello world, !] 如果添加的元素不是String类型,则会直接编译不通过 */ Collection<String> c = new ArrayList<>(); c.add("hello world"); c.add("!"); System.out.println(c); } }
ArrayList是一个集合类,可以存储多个重复的元素,且底层是一个数组
ArrayList类的构造方法:
1、无参构造器
public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; } // DEFAULTCAPACITY_EMPTY_ELEMENTDATA 是一个空数组
在使用无参构造器创建对象时,在底层的数组会是一个空数组
当添加第一个元素时,它会自动扩容成含有10个容量的数组
可以发现,数组的容量发生了变化
查阅源码得到
private static int calculateCapacity(Object[] elementData, int minCapacity) { if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { return Math.max(DEFAULT_CAPACITY, minCapacity); } return minCapacity; } //DEFAULT_CAPACITY数值为10 无参构造器minCapacity=0
会得到一个容量为10的数组
2、有参构造器
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集合类的扩容
实质:对底层数组的更新,通过Arrays.copyOf返回一个新的长度的数组
扩容的细节:1、使用无参构造器构造对象,初始化容量为0,第一次添加元素,则扩容为10,如果还需要再次扩容,则扩大为1.5倍
2、使用有参构造器构造对象,初始化容量为指定的大小,如果需要扩容,则直接扩大1.5倍
Collection中定义的一些抽象方法,在这里具体通过ArrayList创建的对象,所以这里的方法我们认为是ArrayList重写Collection的方法
ArrayList类中的add 方法
源码:
public boolean add(E e) { ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true; }
对源码的解释说明:
1、ArrayList集合类的底层是一个数组:transient Object[] elementData;
elementData数组存储着元素,ArrayList类对它进行维护
2、在进行添加元素之前需要先进行一个判断,判断这个底层数组是否已经被装满,如果被装满就需要对数组进行扩容,如果没有就直接在末尾添加元素即可
判断是否需要扩容的源码
private void ensureExplicitCapacity(int minCapacity) { modCount++; // overflow-conscious code if (minCapacity - elementData.length > 0) grow(minCapacity); }
3、因为集合可以动态扩容,所以需要有个变量来记录存储了多少元素,size来记录已经存储的元素的个数
ArrayList类中的size 方法
作用:得到ArrayList对象中的元素个数
格式:对象名.size();
实例演示:
public class Test { public static void main(String[] args) { ArrayList list = new ArrayList(); list.add("中"); list.add("国"); System.out.println(list.size()); /* 结果:2 */ } }
ArrayList类中的get 方法
作用:通过索引取得索引位置上的元素
格式:对象名.get(int index);
实例演示:
public class Test { public static void main(String[] args) { ArrayList list = new ArrayList(); list.add("中"); list.add("国"); System.out.println(list.get(0)); /* 结果:中 */ } }
ArrayList类中的indexOf方法
作用:返回此列表中指定元素的第一次出现的索引,如果此列表不包含元素,则返回-1
格式:对象名.indexOf(Object o);
实例演示:
public class Test { public static void main(String[] args) { ArrayList list = new ArrayList(); list.add("中"); list.add("国"); System.out.println(list.indexOf("中")); } }
类似的方法还有:
对象名.remove(int index); 删除并返回指定索引的元素
对象名.remove(Object o); 删除指定的对象并返回布尔值,如果删除成功则返回true,否则返回false
对象名.set(int index,Object o); 用指定的对象替换指定索引位置的元素
ArrayList类中的sort 方法
作用:对数组元素按照比较器排序
格式:对象名.sort(Comparator<? super E> c)
sort括号中接口的定义
方法一:匿名内部类
public class Test { public static void main(String[] args) { ArrayList<Integer> alist = new ArrayList<>(); alist.add(1); alist.add(0); alist.add(-3); alist.sort(new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { return o2-o1; } }); System.out.println(alist); } }
方法二:创建类来实现
public class Test { public static void main(String[] args) { ArrayList<Integer> alist = new ArrayList<>(); alist.add(1); alist.add(0); alist.add(-3); ComparatorDemo c = new ComparatorDemo(); alist.sort(c); System.out.println(alist); } } class ComparatorDemo implements Comparator<Integer>{ @Override public int compare(Integer o1, Integer o2) { return o1-o2; } }
方法三:直接将方法作为参数
public class Test { public static void main(String[] args) { ArrayList<Integer> alist = new ArrayList<>(); alist.add(1); alist.add(0); alist.add(-3); alist.sort((Integer o1,Integer o2)->{ return o1-o2; }); System.out.println(alist); } }
未完待续......