java基础学习笔记(四)_Collection_Map

  1. 为什么需要集合:
    Java数组虽然能够存储元素,且可以存储基本数据类型和引用类型,但是数组一旦创建,其长度不可以改变,添加元素和删除元素的效率是非常低的,造成大量元素的移动,比如新闻类的网站,你知道今天会有多少新闻吗?那数组长度该定义多少呢?所以使用数组具有一定的局限性
  2. 容器框架
    Java 集合框架提供了一套性能优良、使用方便的接口和类,它们位于 java.util 包中
    存放在集合中的数据,被称为元素(element),集合中只能存储对象,也就是引用类型的

  3. 各接口的特点
    Collection 接口存储一组 不唯一,无序 的对象
    List 接口存储一组不唯一,有序( 索引顺序 )的对象
    Set 接口存储一组唯一,无序的对象
  4. List接口_ArrayList用法详解
    1. 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
          }
      }

       

    2. ArrayList的源码分析
      1. 构造方法                                                                                                                                                                 
        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];
                } 
            }
      2. 添加方法
        //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);
            }

         

      3. 扩容的原理
        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

         

      4. 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++;
            }
      5. get(int index)
        在object类型数组中根据索引取出数组对象
        public E get(int index) {
                rangeCheck(index);
        
                return elementData(index);
            }
        
        E elementData(int index) {
                return (E) elementData[index];
            }
      6. 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];
            }
      7. size()
        用于记录集合中元素的个数
        public int size() {
                return size;
            }
      8. isEmpty()
        集合中一个元素都没有,集合就是空的
        public boolean isEmpty() {
                return size == 0;
            }
      9. 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;
            }
      10. clear()
        public void clear() {
                modCount++;
        
                // clear to let GC do its work
                for (int i = 0; i < size; i++)
                    elementData[i] = null;
        
                size = 0;
            }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值