- 为什么需要集合:
Java数组虽然能够存储元素,且可以存储基本数据类型和引用类型,但是数组一旦创建,其长度不可以改变,添加元素和删除元素的效率是非常低的,造成大量元素的移动,比如新闻类的网站,你知道今天会有多少新闻吗?那数组长度该定义多少呢?所以使用数组具有一定的局限性
- 容器框架
Java 集合框架提供了一套性能优良、使用方便的接口和类,它们位于 java.util 包中存放在集合中的数据,被称为元素(element),集合中只能存储对象,也就是引用类型的
- 各接口的特点
Collection 接口存储一组 不唯一,无序 的对象List 接口存储一组不唯一,有序( 索引顺序 )的对象Set 接口存储一组唯一,无序的对象
- List接口_ArrayList用法详解
- ArrayList的用法:底层数据结构是数组,添加删除效率低
public class TestArrayList { public static void main(String[] args) { //<1>添加 List list=new ArrayList<>(); list.add("hello"); list.add(123);//自动装箱 list.add(new Scanner(System.in)); //<2>集合长度 System.out.println(list.size());//输出3 //<3>集合是否为空 System.out.println(list.isEmpty());//输出false List list2=new ArrayList(); list2.add("hello"); list2.add("123"); //<4>addAll(Collection c) list.addAll(list2);//相当于list集合中又添加了一个另一个list集合中的元素,所以长度是5 //list.add(list2);//相当于list集合中又添加了一个list,所以长度为4 System.out.println(list.size());//输出5 System.out.println(list);//输出[hello, 123, java.util.Scanner, hello, 123] //<5>删除 System.out.println("根据对象删除"); list.remove("hello");//根据对象删除,删除第一个为hello的对象 System.out.println(list);//输出[123, java.util.Scanner, hello, 123] //list.remove(123);//不能识别,以为是以索引删除的 list.remove(new Integer(123)); System.out.println(list);//输出[java.util.Scanner, hello, 123] System.out.println("根据索引删除"); list.remove(0); System.out.println(list);//输出[hello, 123] list.add("world"); System.out.println(list);//输出[hello, 123,world] //删除所有和list2相同的元素 // list.removeAll(list2); list.retainAll(list2);//删除所有和list2不同的元素 System.out.println(list);//输出[hello, 123] //<6>判断元素是否在集合中存在 System.out.println("hello在集合中是否存在:"+list.contains("hello"));//输出true System.out.println(list.containsAll(list2));//是否包含list2中的全部元素,输出true //<7>清除集合中所有元素对象 //list.clear(); //<8>指定索引操作元素 list.get(1); list.set(1,"java");//原来是[hello, 123],set就把指定位置元素删了 list.add(1,"html"); System.out.println(list);//输出[hello, html, java] //<10>查找元素的位置 System.out.println(list.indexOf("java"));//输出2 //<11>遍历集合中的元素 System.out.println("使用加强for循环遍历"); for(Object obj:list){ System.out.println(obj);//输出[hello, html, java] } System.out.println("使用普通for循环"); for(int i=0;i<list.size();i++){ System.out.println(list.get(i));//输出[hello, html, java] } System.out.println("使用迭代器正向遍历"); Iterator its=list.iterator(); while (its.hasNext()){ System.out.println(its.next());//输出[hello, html, java] } System.out.println("使用迭代器正向遍历"); ListIterator it=list.listIterator(); while (it.hasNext()){ System.out.println(it.next());//输出[hello, html, java] } System.out.println("已经到底集合末尾,后面还有元素吗?"+it.hasNext());//输出false System.out.println("已经到集合末尾,前面还有元素吗?"+it.hasPrevious());//输出true System.out.println("使用迭代器逆向遍历"); while (it.hasPrevious()){ System.out.println(it.previous());//输出[java, html, hello] } System.out.println("到达集合开头,后面还有元素吗?"+it.hasNext());//输出true System.out.println("到达集合开头,前面还有元素吗?"+it.hasPrevious());//输出false } }
- ArrayList的源码分析
- 构造方法
this.elementData是一个Object类型的数组 DEFAULTCAPACITY_EMPTY_ELEMENTDATA也是一个Object类型的数组 DEFAULTCAPACITY_EMPTY_ELEMENTDATA={};在堆区开了内存,只是长度为0 public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; } 如果initialCapacity=20,则创建一个长度为20的Object数组 public ArrayList(int initialCapacity) { if (initialCapacity > 0) { this.elementData = new Object[initialCapacity]; } }
- 添加方法
//size是集合当中元素的个数, ensureCapacityInternal(size + 1); 检测空间容量是否够用 构造函数为空参数的时候,size=0,也就是最小需要1个空间 在数组的size位置将元素添加进去,然后size++ (size + 1)是我所需的最小容量 调用ensureCapacityInternal,把所需的最小容量改为10 public boolean add(E e) { ensureCapacityInternal(size + 1); elementData[size++] = e; return true; } //第一次调用 add()方法, DEFAULT_CAPACITY = 10; elementData={} DEFAULTCAPACITY_EMPTY_ELEMENTDATA={} ensureCapacityInternal方法给首先给我们计算出了我们所需的最小容量是10 private void ensureCapacityInternal(int minCapacity) { if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); } ensureExplicitCapacity(minCapacity); } ensureExplicitCapacity(10); 我们所需的最小容量是10,数组长度是0,所以需要grow扩容 private void ensureExplicitCapacity(int minCapacity) { modCount++; // overflow-conscious code if (minCapacity - elementData.length > 0) grow(minCapacity); }
- 扩容的原理
oldCapacity=0 newCapacity = oldCapacity + (oldCapacity >> 1) =0 newCapacity新的容量是0,新的容量-所需的最小容量为0,所以赋值新的容量为10 elementData = Arrays.copyOf(elementData, newCapacity); 数组拷贝完成后,elementData的新的长度就是10了 private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; int newCapacity = oldCapacity + (oldCapacity >> 1); if (newCapacity - minCapacity < 0) newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); // minCapacity is usually close to size, so this is a win: elementData = Arrays.copyOf(elementData, newCapacity); } 以上是第一次调用add方法时,完成elementData数组的初始化容量是10 第二次调用add方法时,数组长度为10,所需的最小容量为2,所以不执行grow方法 当你添加到11个元素的时候,在进行扩容,扩容到15
-
add(int index,Object obj)
rangeCheckForAdd(index);检测索引 ensureCapacityInternal(size + 1); 检测容量是否够用 进行数组拷贝 原数组 原数组开始位置,新数组,新数组开始位置,拷贝长度 elementData[index] = element;将元素添加到索引为index的位置上 public void add(int index, E element) { rangeCheckForAdd(index); ensureCapacityInternal(size + 1); // Increments modCount!! System.arraycopy(elementData, index, elementData, index + 1, size - index); elementData[index] = element; size++; }
-
get(int index)
在object类型数组中根据索引取出数组对象 public E get(int index) { rangeCheck(index); return elementData(index); } E elementData(int index) { return (E) elementData[index]; }
-
set(int index,Object obj)
E oldValue = elementData(index);返回原来在这个位置上的元素 elementData[index] = element;将新元素设置到数组索引为index的位置上 public E set(int index, E element) { rangeCheck(index); E oldValue = elementData(index); elementData[index] = element; return oldValue; } E elementData(int index) { return (E) elementData[index]; }
-
size()
用于记录集合中元素的个数 public int size() { return size; }
-
isEmpty()
集合中一个元素都没有,集合就是空的 public boolean isEmpty() { return size == 0; }
-
remove(int index)
返回的是一个删除元素 public E remove(int index) { rangeCheck(index); modCount++; E oldValue = elementData(index); int numMoved = size - index - 1; if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); elementData[--size] = null; // clear to let GC do its work return oldValue; }
-
clear()
public void clear() { modCount++; // clear to let GC do its work for (int i = 0; i < size; i++) elementData[i] = null; size = 0; }
- 构造方法
- ArrayList的用法:底层数据结构是数组,添加删除效率低
java基础学习笔记(四)_Collection_Map
最新推荐文章于 2020-11-16 14:51:29 发布