首页 > 编程语言 >Java小白一文讲清Java中集合相关的知识点(二)

Java小白一文讲清Java中集合相关的知识点(二)

时间:2024-09-02 18:52:37浏览次数:6  
标签:知识点 Java ArrayList list System 讲清 add println out

List

List接口和常用方法

基本介绍

List接口是Collection接口的子接口

  • List集合类中的元素有序–即添加顺序和取出顺序一致、且可重复
public class Journey {
    @SuppressWarnings({"all"})
    public static void main(String[] args) {
        List list = new ArrayList();
        list.add("kerwin");
        list.add("A");
        list.add("B");
        list.add("C");
        list.add("kerwin");
        list.add(true);
        System.out.println("list="+list);
    }
}
//输出
list=[kerwin, A, B, C, kerwin, true]
  • List集合中的每一个元素都有其对应的顺序索引,即支持索引
@SuppressWarnings({"all"})
    public static void main(String[] args) {
        List list = new ArrayList();
        list.add("kerwin");
        list.add("A");
        list.add("B");
        list.add("C");
        list.add("kerwin");
        list.add(true);
        System.out.println("list="+list);

        System.out.println(list.get(2));//B
    }
  • List容器中的元素都对应一个整数型的序号记载其在容器中的位置,可以根据序号存取容器中的元素
  • List接口的实现类有ArrayList 、 LinkedList 、Vector
常用方法

在这里插入图片描述

import java.util.ArrayList;
import java.util.List;

public class Journey {
    @SuppressWarnings({"all"})
    public static void main(String[] args) {
        List list = new ArrayList();
        list.add("kerwin");
        list.add("A");
        list.add(true);
        list.add(0,"Blue");
        System.out.println("list="+list);//输出如下
//        list=[Blue, kerwin, A, true]

        List list2 = new ArrayList();
        list2.add(false);
        list2.add(1110);
        list2.addAll(0,list);
        System.out.println("list2="+list2);//输出如下
//        list2=[Blue, kerwin, A, true, false, 1110]

        System.out.println(list.get(0));//Blue
        System.out.println(list2.get(4));//false

        System.out.println(list.indexOf("Blue"));//0

        list.add("kerwin");
        System.out.println("第二次新加了个元素kerwin后的list="+list);//输出如下
//        第二次新加了个元素kerwin后的list=[Blue, kerwin, A, true, kerwin]

        System.out.println(list.lastIndexOf("kerwin"));//4
        System.out.println(list.indexOf("kerwin"));//1

        list.remove("Blue");
        System.out.println("移除了一个元素后的list="+list);
//        移除了一个元素后的list=[kerwin, A, true, kerwin]

        System.out.println(list.set(0, "A"));//设置指定的index 0 位置处的元素为 A,输出 kerwin
        //如果.set(index,ele)中的index不存在则会报数组越界异常,所以index必须存在才行
        System.out.println(list);//此时输出如下
//        [A, A, true, kerwin]

        System.out.println(list.subList(1, 3));//输入如下,取[1,3)区间的元素
//          [A, true]

    }
}

练习
在这里插入图片描述

public class Journey {
    @SuppressWarnings({"all"})
    public static void main(String[] args) {
        List list = new ArrayList();
        list.add("kerwin");
        list.add(1110);
        list.add(true);
        list.add("hello");
        list.add(1110);
        list.add(3.14);
        System.out.println("list="+list);
//        list=[kerwin, 1110, true, hello, 1110, 3.14]

        //在3号位插入hsp,注意3号位是指第三个元素,其索引是2,list中的索引是从0开始的哈
        list.add(2,"hsp");
        System.out.println("添加了hsp后的list="+list);
//        添加了hsp后的list=[kerwin, 1110, hsp, true, hello, 1110, 3.14]

        //获得第5个元素
        System.out.println(list.get(4));//hello

        //删除第6个元素
        list.remove(5);//1110
        System.out.println("list="+list);
//        list=[kerwin, 1110, hsp, true, hello, 3.14]

        //修改第7个元素
        System.out.println(list.size());//6
        list.add("我是第七个元素");
        System.out.println(list);
//        [kerwin, 1110, hsp, true, hello, 3.14, 我是第七个元素]
        list.set(6,"我是被改动之后的七号元素");
        System.out.println("此刻的list="+list);
//        此刻的list=[kerwin, 1110, hsp, true, hello, 3.14, 我是被改动之后的七号元素]

        //使用迭代器遍历集合
        System.out.println("使用迭代器遍历,可得:=======================");
        //创建迭代器,注意不是直接new哈
        Iterator iterator = list.iterator();
        //联想到迭代器的结构,判断是否还有下一个元素,若有,则下移,并return取出
        //顺便一提,可以用快捷键一键生成itit
        while (iterator.hasNext()) {
            Object obj = iterator.next();
            System.out.println(obj);
        }
        //输出如下
        /**
         * kerwin
         * 1110
         * hsp
         * true
         * hello
         * 3.14
         * 我是被改动之后的七号元素
         */


    }
}

List的三种遍历方式

【ArrayList、LinkedList、Vector】

说明:使用LinkedList完成 ,其使用方式和ArrayList一样

public class Journey {
    @SuppressWarnings({"all"})
    public static void main(String[] args) {
        //下面三种List接口的实现子类都可以完美适配底下三种遍历方式
//        LinkedList list = new LinkedList();
//        List list = new Vector();
        List list = new ArrayList();
        for (int i = 0; i < 5; i++) {
            list.add(i);
        }
        list.add("bingo!!");
        System.out.println(list);

        //1.使用迭代器遍历
        Iterator iterator = list.iterator();
        while (iterator.hasNext()) {
            Object obj = iterator.next();
            System.out.println("obj=" + obj);
        }
        System.out.println("+++++++++++++++++++++++++++++++++++++++");
        //2.使用增强for循环
        for (Object o : list) {
            System.out.println("增强for得到元素-->" + o);
        }
        System.out.println("========================================");
        //3.使用普通for循环
        for (int i = 0; i < list.size(); i++) {
            System.out.println("normalFor===》" + list.get(i));
        }
    }
}
练习

在这里插入图片描述

public class Journey {
    @SuppressWarnings({"all"})
    public static void main(String[] args) {
        //使用ArrayList实现
//        List list = new ArrayList();
        //使用Vector实现
//        List list = new Vector();
        //使用LinkedList实现
        List list = new LinkedList();
        list.add(new Book("红楼梦","曹雪芹",100));
        list.add(new Book("西游记","吴承恩",10));
        list.add(new Book("水浒传","施耐庵",19));
        list.add(new Book("三国志","罗贯中",80));
        list.add(new Book("西游记","吴承恩",10));


        for (Object o :list) {
            System.out.println(o);
        }
        //遍历结果如下:
        /**
         * 名称:红楼梦		价格:100.0		作者:曹雪
         * 名称:西游记		价格:10.0		作者:吴承恩
         * 名称:水浒传		价格:19.0		作者:施耐庵
         * 名称:三国志		价格:80.0		作者:罗贯中
         * 名称:西游记		价格:10.0		作者:吴承恩
         */

        //按价格排序,从高到低
        //如何对集合进行排序呢?
        sort(list);
        System.out.println("======排序后的输出=======");
        for (Object o :list) {
            System.out.println(o);
        }
        //输出结果如下
        /**
         * ======排序后的输出=======
         * 名称:西游记		价格:10.0		作者:吴承恩
         * 名称:西游记		价格:10.0		作者:吴承恩
         * 名称:水浒传		价格:19.0		作者:施耐庵
         * 名称:三国志		价格:80.0		作者:罗贯中
         * 名称:红楼梦		价格:100.0		作者:曹雪芹
         */

    }
    //静态方法
    @SuppressWarnings({"all"})
    public static void sort(List list){
        //使用冒泡排序框架
        int size = list.size();
        for(int e=size-1;e>0;e--){
            for(int j=0;j<e;j++){
                //取出对象
//                Object o = list.get(j);
                //注意这里要向下转型,不然不是Book对象,咋获得其属性呢?
                //这里不需要使用中间变量哈,可以直接用set实现互换
                Book book1 = (Book)list.get(j);//原先的list.get(j)的返回类型是Object类型的
                Book book2 = (Book)list.get(j+1);
                if(book1.getPrice()>book2.getPrice()){
                    list.set(j,book2);
                    list.set(j+1,book1);
                }
            }
        }
    }
}

ArrayList的注意事项

  • 可以存放所有类型的元素,甚至是空元素null,ArrayList并且可以放入多个元素
public static void main(String[] args) {
        ArrayList list = new ArrayList();
        list.add(null);
        list.add("kerwin");
        list.add(null);
        for (Object o :list) {
            System.out.println(o);

        }
        /**
         * null
         * kerwin
         * null
         */
    }
  • ArrayList是由数组来实现数据存储的

  • ArrayList基本等同于Vector,除了ArrayList是线程不安全(但是其执行效率高啊hhhh)的外;

    在多线程情况下,不建议使用ArrayList

 	//ArrayList是线程不安全的,以下是其add方法源码,可见并没有同步关键字修饰
	public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }
	
	//而这是Vector底层的add方法源码,可以看到是有同步关键字synchronized修饰的
	public synchronized void addElement(E obj) {
        modCount++;
        ensureCapacityHelper(elementCount + 1);
        elementData[elementCount++] = obj;
    }

ArrayList底层操作机制源码分析

@SuppressWarnings({"all"})
public class Journey {
    public static void main(String[] args) {
        //使用无参构造器创建ArrayList对象
        ArrayList list = new ArrayList();
//        ArrayList list = new ArrayList(8);

        for (int i = 1; i <=10; i++) {
            list.add(i);//这里会自动装箱,进入Integer的valueOf方法
            //之后,再执行这个add方法,而add方法内部也不是上来就把元素丢进数组里,
            //而是先通过ensureCapacityInternal方法来确保加了一个元素后,不会越界
            //然后才放进elementData数组中
        }

        for (int i = 11; i <= 15; i++) {
            list.add(i);
        }
        list.add(100);
        list.add(200);
        list.add(null);
        for (Object o :list) {
            System.out.println(o);

        }

    }
}
  • ArrayList中维护了一个Object类型的数组elementData

    拓展:transient–瞬间的、短暂的,其表示被transient修饰的属性不会被序列化,会被忽略

	public ArrayList() {
        //创建了一个空的elementData数组={}
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
        //这里再进入,就会发现起初这里传给它的DEFAULTCAPACITY_EMPTY_ELEMENTDATA是一个{}
    }
  • 当创建ArrayList对象时,如果使用的是无参构造器,则初始elementData容量为0,第一次添加,则扩容elementData为10,如需要再次扩容,则扩容elementData为1.5倍
//calculateCapacity()--->grow()--->ensureExplicitCapacity()-->ensureCapacityInternal()--->add()
/**
调用顺序总结:
calculateCapacity() 计算出所需的最小容量。
结果传递给 ensureExplicitCapacity(),判断是否需要扩容。
如果需要扩容,ensureExplicitCapacity() 调用 grow() 方法进行扩容。
扩容完成后,所有调用链返回到 add() 方法,最终新元素被成功添加。
*/
	public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;//最后完成第一次扩容后,elementData就有了10个空间,size起初等于0,
        					  //把要放的数据放进去,然后size++,变为1,表示此时的数组中有了一个数据
        return true;
    }

    private void ensureCapacityInternal(int minCapacity) {//注意这里是最少需要的容量,比如你第一次add,那么最少需要一个
        //容量,嗯哼?如果你加了10个元素了,那么再add一次,底层到这儿就会是11个,因为只有11个才能将你之前的10个和
        //现在准备新add的那一个元素全放进去;
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }

    private static int calculateCapacity(Object[] elementData, int minCapacity) {
        //如果当前数组是默认的空数组,则直接返回max(默认初始化的容量10,当前所需要的容量),否则返回所需容量
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            //DEFAULT_CAPACITY这里是10,而minCapacity是1
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        //这里的minCapacity是当前需要的最小容量,你当前要加进去一个元素,自然这里的值就是1了
        return minCapacity;
    }

    private void ensureExplicitCapacity(int minCapacity) {
        //这里记录的是被修改的次数
        modCount++;

        // overflow-conscious code
        if (minCapacity - elementData.length > 0)//10-0>0,所以进入动态扩容机制
            grow(minCapacity);
    }

	 private void grow(int minCapacity) {
        // overflow-conscious code
         //获取当前数组的容量
        int oldCapacity = elementData.length;//0
         //新数组扩容为原来的1.5倍,这里我们是第一次扩容,所以走的是第一个if逻辑分支
        int newCapacity = oldCapacity + (oldCapacity >> 1);//0+0/2=0
         //检查新的容量是否满足最小需求minCapacity,
         //如果不满足,也就是扩容后小于所需容量,则直接将 newCapacity 
         //设置为 minCapacity。这样可以确保扩容后的数组至少能容纳当前所有的元素。
        if (newCapacity - minCapacity < 0)//0<10,所以newCapacity就被赋成10了;
            newCapacity = minCapacity;
         //检查是否超过最大允许的数组大小
         //如果新的容量超过了这个最大值,就调用 hugeCapacity(minCapacity),
         //可能会根据系统的限制或特定情况处理超大数组的分配。
        if (newCapacity - MAX_ARRAY_SIZE > 0)//此时不满足,所以跳过
            newCapacity = hugeCapacity(minCapacity);

         //复制数组到新容量,elementData起初是{},newCapacity是10,
         //随后elementData容量就成了10,里面是空数据
        elementData = Arrays.copyOf(elementData, newCapacity);
         //这里的扩容是保留原有数据的前提下,再给你多搞几个空间出来,
         //类似于给你搬家,换个大房子,原先的东西也一并带过来
    }


扩容机制的要点

初始容量:在首次添加元素时,ArrayList 会初始化其内部数组到默认容量(10)。

动态扩容:每当数组需要扩容时,ArrayList 会扩展到原来容量的 1.5 倍,以减少频繁扩容的开销。

最小容量保证:扩容后的新容量至少满足当前所需的最小容量 minCapacity

最大容量检查:确保扩容后的容量不超过 JVM 所能支持的最大数组大小。

数组复制:通过扩展数组并复制原有数据,ArrayList 保证了动态数组的灵活性和稳定性。

  • 如果使用的是指定大小的构造器,则初始elementData的容量大小为指定大小,如果需要再次扩容,则直接扩容elementData为1.5倍
@SuppressWarnings({"all"})
public class Journey {
    public static void main(String[] args) {
        //使用有参构造器创建ArrayList对象
        ArrayList list = new ArrayList(8);

        for (int i = 1; i <=10; i++) {
            list.add(i);//这里会自动装箱,进入Integer的valueOf方法
            //之后,再执行这个add方法,而add方法内部也不是上来就把元素丢进数组里,
            //而是先通过ensureCapacityInternal方法来确保加了一个元素后,不会越界
            //然后才放进elementData数组中
        }

        for (int i = 11; i <= 15; i++) {
            list.add(i);
        }
        list.add(100);
        list.add(200);
        list.add(null);
        for (Object o :list) {
            System.out.println(o);

        }

    }
}

//debug源码,进入ArrayList的内部,如下,此时指定的容量是8,所以走第一个分支,给elementData扩容成8
    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);
        }
    }

标签:知识点,Java,ArrayList,list,System,讲清,add,println,out
From: https://blog.csdn.net/Kerwin_D/article/details/141790685

相关文章

  • 【Java 基础】类和对象(构造&this&封装&static&代码块)
    ✨                           风起于青萍之末,浪成于微澜之间    ......
  • Java开发语言:ssm人力资源管理系统010(附免费源码)
    摘 要科技进步的飞速发展引起人们日常生活的巨大变化,电子信息技术的飞速发展使得电子信息技术的各个领域的应用水平得到普及和应用。信息时代的到来已成为不可阻挡的时尚潮流,人类发展的历史正进入一个新时代。在现实运用中,应用软件的工作规则和开发步骤,采用Java技术建设人......
  • 【Java】—— Java面向对象进阶:Java中的账户管理-基础账户与可透支账户的实现与测试
    目录1.基础账户类(Account)2.测试基础账户类3.可透支账户类(CheckAccount)4.测试可透支账户类运行结果1.基础账户类(Account)        写一个名为Account的类模拟账户。该类的属性和方法如下图所示。该类包括的属性:账号id,余额balance,年利率annualInterestRate;......
  • 高级java每日一道面试题-2024年9月02日-基础篇-什么是脏读、不可重复读和幻读?
    如果有遗漏,评论区告诉我进行补充面试官:什么是脏读、不可重复读和幻读?我回答:在数据库事务的并发控制中,脏读(DirtyRead)、不可重复读(Non-repeatableRead)和幻读(PhantomRead)是三种常见的并发问题,它们主要涉及到事务的隔离级别和一致性。了解这些问题有助于我们设计更健......
  • 高级java每日一道面试题-2024年9月02日-基础篇-如何处理嵌套事务?
    如果有遗漏,评论区告诉我进行补充面试官:如何处理嵌套事务?我回答:处理嵌套事务(NestedTransactions)是Java开发中一个常见的问题,特别是在涉及多个数据库操作时。嵌套事务指的是在一个事务中又开始了另一个事务,形成了事务的层次结构。处理嵌套事务需要特别注意事务的边界......
  • JAVA List<Map<String, Object>> sort 多个排序写法
     基本方法/***排序=**@paramlist*@paramsort_key*@return*/publicstaticList<Map<String,Object>>sort(List<Map<String,Object>>list,Stringsort_key,Booleanasc,Stringsort_key2,Boole......
  • Java平衡树--查找树的新建与树的实现
    Java学习+面试指南:https://javaxiaobear.cn1、查找树的定义一棵2-3查找树要么为空,要么满足满足下面两个要求:2-结点含有一个键(及其对应的值)和两条链,左链接指向2-3树中的键都小于该结点,右链接指向的2-3树中的键都大于该结点。3-结点含有两个键(及其对应的值)和三条链,左链接指向的2......
  • Java 最小优先队列API设计与实现
    Java学习+面试指南:https://javaxiaobear.cn最小的元素放在数组的索引1处。每个结点的数据总是小于等于它的两个子结点的数据。1、API设计类名MinPriorityQueue构造方法MinPriorityQueue(intcapacity):创建容量为capacity的MinPriorityQueue对象成员方法privatebooleanless(inti......
  • Java 堆的设计,如何用堆进行排序
    Java学习+面试指南:https://javaxiaobear.cn1、堆的定义堆是计算机科学中一类特殊的数据结构的统称,堆通常可以被看做是一棵完全二叉树的数组对象。1、堆的特性它是完全二叉树,除了树的最后一层结点不需要是满的,其它的每一层从左到右都是满的,如果最后一层结点不是满的,那么要求左满右......
  • Java最大优先队列设计与实现
    Java学习+面试指南:https://javaxiaobear.cn1、API设计类名MaxPriorityQueue构造方法MaxPriorityQueue(intcapacity):创建容量为capacity的MaxPriorityQueue对象成员方法privatebooleanless(inti,intj):判断堆中索引i处的元素是否小于索引j处的元素privatevoideach(inti,int......