Java学习笔记_集合

集合

集合与数组的相似点:

  • 都可以存储多个对象。对外作为一个整体存在

数组的缺点:

  • 长度必须在初始化是指定,且固定不变
  • 数组采用连续存储空间,删除和添加效率低下
  • 数组缺乏封装,操作繁琐

集合架构:

  • Collection接口存储一组不唯一,无序的对象
  • List接口存储一组不唯一,有序(索引顺序)的对象
  • Set接口存储一组唯一,无序的对象
  • Map接口存储一组键值对象,提供Key到value的映射(Key 唯一 无序 )(value 不唯一 无序)

List集合

List集合的主要实现类有ArrayList和LinkedList,分别是数据结构中顺序表和链表的实现。另外还包括栈和队列的实现类:Deque和Queue。

List特点:有序 不唯一(可重复)

ArrayList

ArrayList:

  • 在内存中分配连续的空间,实现了长度可变的数组
  • 优点:遍历元素和随机访问元素的效率比较高
  • 缺点:添加和删除需大量移动元素,效率低,按照内容查询效率
ArrayList的使用:
public class ArrList1 {
    public static void main(String[] args) {
        //定义一个ArrayList集合
        //<泛型>中只能放一个对象,不能放基本类型,所以放int的包装类
        ArrayList<Integer>  list=new ArrayList<>();
        list.add(123);  //往集合里存入数据,jdk5以后提供自动装箱
        list.add(234);
        list.add(456);
        list.add(new Integer(886));

        //从集合里取出单个数据(ArrayList底层是用数组实现,所以用下标取值)
        Integer integer = list.get(3);
        System.out.println(integer);

        //返回集合的长度
        System.out.println(list.size());

        //遍历集合方式一
        for (int i = 0; i <list.size() ; i++) {
            System.out.print(list.get(i)+"\t");
        }

        //遍历集合方式二
        for (Integer arrlist: list) {
            System.out.println(arrlist);
        }
    }

}
ArrayList更多的使用方法:
public class ArrList2 {
    public static void main(String[] args) {
        ArrayList<Integer>  list=new ArrayList<>();
        list.add(1);
        list.add(2);
        list.add(3);

        //可以在指定下标位置添加元素,【下标,元素】
        list.add(1,23);

        ArrayList<Integer>  list2=new ArrayList<>();
        list2.add(888);
        list2.add(999);

        //把List2中的元素全部存储到List中
        list.addAll(list2);

        //修改指定下表元素
        list.set(0,11);

        //删除指定下表元素
        list.remove(1);
        //删除指定内容元素
        list.remove(new Integer(3));

        //删除整个数组
        list.removeAll(list2);

        //清空集合
        //list.clear();

        //判断集合是否为空
        boolean empty = list.isEmpty();
        System.out.println(empty);

        //判断集合是否包含指定元素
        boolean contains = list.contains(555);
        System.out.println(contains);
        
        System.out.println("集合输出:"+list.toString());
    }
}
理解ArrayList的底层源码:
/*
ArrayList底层源码解析:
    当  ArrayList<Integer>  list=new ArrayList<>();  时
    底层发生了什么?
 */
   //1.  进入ArrayList方法
       public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
       }
  // 2.  进入 elementData
        transient Object[] elementData;

  // 3.   进入DEFAULTCAPACITY_EMPTY_ELEMENTDATA
        private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

 /*  
   所以 Object[] elementData={};
   底层创建一个空数组,长度为0,如果用户在集合中增加内容,那么这时候数组直接进行扩容

   那么底层的数组是如何进行扩容的?
  */ 
   //1.  进入add方法
       public boolean add(E e) {
       ensureCapacityInternal(size + 1);  // Increments modCount!!
       elementData[size++] = e;
       return true;
       }
       
    //2.  进入ensureCapacityInternal方法
        private void ensureCapacityInternal(int minCapacity) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
       }
       
    // 3.  进入calculateCapacity方法
        private static int calculateCapacity(Object[] elementData, int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        return minCapacity;
    }
    
      4.   DEFAULTCAPACITY_EMPTY_ELEMENTDATA={};
         DEFAULT_CAPACITY=10;
         
    //5.  进入ensureExplicitCapacity方法
        private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
       }
       
    // 6.  进入grow方法
        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);
       }
       
       //7. 进入hugeCapacity方法
       private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }
/* 如果我们第一次在数组中添加数据,这个时候底层会给数组长度为10。     
   我们后续添加的内容如果超出了长度会进行二次扩容,增加50%,即新数组为旧数组的1.5倍。     
   如果增加了50%不够用,那么会直接使用新内容的长度作为新数组的长度,如果新增内容超过数组最大长度, 抛出异常
 */

//底层是如何用get方法获取数据的呢?
1.进入get方法:
    public E get(int index) {
        rangeCheck(index);

        return elementData(index);
    }
2.进入rangeCheck(index)方法:
    private void rangeCheck(int index) {
        if (index >= size)     //给定的下标超过数组长度,也就是数组越界,抛出异常
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }
3.进入elementData(index)方法:
    E elementData(int index) {
        return (E) elementData[index];  //直接返回数组下标对应的值
    }
ArrayList在JDK1.7和1.8中的区别

JDK1.7中,使用无参构造方法创建ArrayList对象时,默认底层数组长度是10。

JDK1.8中,使用无参构造方法创建ArrayList对象时,默认底层数组长度是0;第一次添加元素,容量不足就要扩容,这样是为了避免创建集合不添加数据而造成的资源浪费。

LinkedList

LinkedList:

  • 采用双链表存储的方式
  • 缺点:插入、删除元素效率比较高(但是前提也是必须先低效率查询才可。如果插入删除发生在头尾可以减少查询次数)
LinkedList的使用:
public class LinkedList1 {
    public static void main(String[] args) {
        LinkedList<Integer>    list=new LinkedList<>();
        list.add(123);
        list.add(456);
        list.add(789);
        list.addFirst(333); //在第一个位置添加元素
        list.addLast(888); //在最后一个位置添加元素
        list.add(1,911); //在中间指定位置添加元素

        list.remove(0);//删除指定元素
        list.removeFirst();//删除第一个元素
        list.removeLast();//删除最后一个元素

        list.getFirst();//获取第一个元素
        list.getLast();//获取最后一个元素


        System.out.println(list.toString());

    }
}
理解LinkedList的底层源码:

在这里插入图片描述

//LinkedList底层源码:
    //进入LinkedList<>
    transient int size = 0;
    transient Node<E> first;
    transient Node<E> last;

  // 1.进入add方法
     public boolean add(E e) {
        linkLast(e);
        return true;
     }
  // 2.进入 linkLast方法
    void linkLast(E e) {
        final Node<E> l = last;
        final Node<E> newNode = new Node<>(l, e, null);
        last = newNode;
        if (l == null)
            first = newNode;
        else
            l.next = newNode;
        size++;
        modCount++;
    }

ArrayList与LinkedList的区别

问题1:将ArrayList替换成LinkedList之后,不变的是什么?

  • 运算结果没有变
  • 执行的功能代码没有变

问题2:将ArrayList替换成LinkedList之后,变化的是什么?

  • 底层的结构变了

    ArrayList:数组 LinkedList:双向链表

  • 具体的执行过程变化了 list.add(2,99)

​ ArrayList:大量的后移元素

​ LinkedList:不需要大量的移动元素,修改节点的指向即可

问题3:到底是使用ArrayList还是LinkedList

  • 根据使用场合而定
  • 大量的根据索引查询的操作,大量的遍历操作(按照索引0–n-1逐个查询一般),建议使用ArrayList
  • 如果存在较多的添加、删除操作,建议使用LinkedList

问题4:LinkedList增加了哪些方法

  • 增加了对添加、删除、获取首尾元素的方法
  • addFirst()、addLast()、removeFirst()、removeLast()、getFirst()、getLast().

Java中栈和队列的实现类

  public static void main(String[] args) {
  //栈   特点:先进后出
        Stack<String>   stack=new Stack<>();

        //入栈
        stack.push("ABC");
        stack.push("SDF");
        stack.push("VBN");

        //栈顶
        System.out.println(stack.peek());

        //出栈
       stack.pop();

  //单端队列  特点:先进先出
        Queue<String>  queue=new LinkedList<>();
        //入队
        queue.offer("01");
        queue.offer("02");
        queue.offer("03");

        System.out.println(queue.peek()); //栈顶

        System.out.println(queue.poll());//出队

 //双端队列
       Deque<String> deque=new LinkedList<>();
      //入队
       deque.push("11");
       deque.push("22");
       deque.push("33");
       deque.push("44");
       //出队
     deque.pop();
     }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值