Java中Collection集合,List集合,ArrayList,LinkedList的遍历和常用方法及部分底层原理和应用场景

一、集合概述和分类

1. 集合的分类

         在Java还提供了很多种其他的集合,如下图所示:

        在Java中,对这些集合进行了分类,一类是单列集合元素是一个一个的(例如,存放学生姓名数据:张三、李四、王五),另一类是双列集合元素是一对一对的(例如存放为学生学号信息数据:1001 张三、1002 李四、1003 王五)。如图:

        在此,本篇主要介绍Collection单列集合。

        Collection接口下面又有两个子接口List接口、Set接口,List和Set下面分别有不同的实现类,如下图所示:

上图中各种集合的特点如下图所示:

通过代码验证以上特点

//简单确认一下Collection集合的特点
ArrayList<String> list = new ArrayList<>(); //存取顺序一致,可以重复,有索引
list.add("java1");
list.add("java2");
list.add("java1");
list.add("java2");
System.out.println(list); //[java1, java2, java1, java2] 

HashSet<String> list = new HashSet<>(); //存取顺序不一致,不重复,无索引
list.add("java1");
list.add("java2");
list.add("java1");
list.add("java2");
list.add("java3");
System.out.println(list); //[java3, java2, java1] 

2. Collection集合的常用功能和方法

        ArrayList、LinkedList、HashSet、LinkedHashSet、TreeSet集合都可以调用下面的方法。

Collection<String> c = new ArrayList<>();
//1.public boolean add(E e): 添加元素到集合
c.add("java1");
c.add("java1");
c.add("java2");
c.add("java2");
c.add("java3");
System.out.println(c); //打印: [java1, java1, java2, java2, java3]

//2.public int size(): 获取集合的大小
System.out.println(c.size()); //5

//3.public boolean contains(Object obj): 判断集合中是否包含某个元素
System.out.println(c.contains("java1")); //true
System.out.println(c.contains("Java1")); //false

//4.pubilc boolean remove(E e): 删除某个元素,如果有多个重复元素只能删除第一个
System.out.println(c.remove("java1")); //true
System.out.println(c); //打印: [java1,java2, java2, java3]

//5.public void clear(): 清空集合的元素
c.clear(); 
System.out.println(c); //打印:[]

//6.public boolean isEmpty(): 判断集合是否为空 是空返回true 反之返回false
System.out.println(c.isEmpty()); //true

//7.public Object[] toArray(): 把集合转换为数组
Object[] array = c.toArray();
System.out.println(Arrays.toString(array)); //[java1,java2, java2, java3]

//8.如果想把集合转换为指定类型的数组,可以使用下面的代码
String[] array1 = c.toArray(new String[c.size()]);
System.out.println(Arrays.toString(array1)); //[java1,java2, java2, java3]

//9.还可以把一个集合中的元素,添加到另一个集合中
Collection<String> c1 = new ArrayList<>();
c1.add("java1");
c1.add("java2");
Collection<String> c2 = new ArrayList<>();
c2.add("java3");
c2.add("java4");
c1.addAll(c2); //把c2集合中的全部元素,添加到c1集合中去
System.out.println(c1); //[java1, java2, java3, java4]

二、Collection遍历方式

        在Collection集合中,通用的普通for方法遍历已经不在适用所有集合,因此存在三种通用的遍历方式:迭代器遍历、增强for遍历、Lambda表达式遍历。

1. Iterator迭代器遍历

       迭代器代码的原理如下:

  • 当调用iterator()方法获取迭代器时,当前指向第一个元素

  • hasNext()方法则判断这个位置是否有元素,如果有则返回true,进入循环

  • 调用next()方法获取元素,并将当月元素指向下一个位置,

  • 等下次循环时,则获取下一个元素,依此类推

    public class IteratorDemo1 {
        public static void main(String[] args) {
    
            Collection<String> coll = new ArrayList<>();
    
            coll.add("aaa");
            coll.add("bbb");
            coll.add("ccc");
            coll.add("ddd");
    
            System.out.println("==========第一次遍历==============");
    
            //迭代器
            Iterator<String> strTt1 = coll.iterator();
    
            //hasNest  判断是否有元素,并返回true(有元素) 和 false(无元素)
            while (strTt1.hasNext()){
                //next 两个作用 1.获取元素  2.移动指针
                String str = strTt1.next();
                System.out.println(str);
            }
    
            //  NoSuchElementException  指针 指向的没有元素,强行通过 next 方法获取  报错 没有元素异常
    //       String str = strTt.next();
    
            System.out.println("============指针不复位===========");
            //Iterator 迭代器对象 遍历完集合后 指针不会复位
            System.out.println(strTt1.hasNext());   // false
    
    
    
            System.out.println("==========第二次遍历==============");
    
            //要再次比遍历只有 重新获取新的 Iterator 迭代器对象
            //新的迭代器
            Iterator<String> strTt2 = coll.iterator();
    
            //hasNest  判断是否有元素,并返回true(有元素) 和 false(无元素)
            while (strTt2.hasNext()){
                //next 两个作用 1.获取元素  2.移动指针
                String str = strTt2.next();
                System.out.println(str);
            }
        }

    注意,在迭代器中,指针无法复位,并且只能使用一次next()方法,

2. 增强for遍历集合

        基于Iterator迭代器简写

public class ForDemo {
    public static void main(String[] args) {
        Collection<String> coll = new ArrayList<>();

        coll.add("aaa");
        coll.add("bbb");
        coll.add("ccc");
        coll.add("ddd");
        System.out.println("=======增强for遍历");
        //在循环遍历中  对变量s的修改 不会影响到集合中的元素
        for (String s : coll) {
            System.out.println(s);
        }
    }
}

3. Lambda表达式遍历(forEach遍历集合)

        基于增强for简写

public class LambdaDemo1 {
    public static void main(String[] args) {
        Collection<String> coll1 = new ArrayList<>();
        coll1.add("aaa");
        coll1.add("bbb");
        coll1.add("bbb");
        coll1.add("ccc");
        coll1.add("ddd");

        System.out.println("=======1========");
        //底层依旧是通过for循环遍历集合 得到每一个元素
        //将得到的每一个元素传递给 accept 方法
        //变量s 依次表示集合中的每一个元素
        coll1.forEach(new Consumer<String>() {
            @Override
            public void accept(String s) {    //变量s 依次表示集合中的每一个元素
                System.out.println(s);
            }
        });


        System.out.println("==========2=========");
        //Lambda表达式    ()->{}
        //()  方法形参  变量S
        //->  指向
        //{}  方法体,即实现 accept 方法的方法体  System.out.println(s);

//        coll1.forEach(new Consumer<String>() {
//            @Override
//            public void accept(String s) {    //变量s 依次表示集合中的每一个元素
//                System.out.println(s);
//            }
//        });


        coll1.forEach(s -> System.out.println(s));

        System.out.println("==========3==========");
        // 方法引用
        coll1.forEach(System.out::println);



    }
}

三、List系列集合

1. List集合的特点  

        Collection下面的一个子体系List集合。如下图所示:

2. List集合的常用方法

        List集合是索引的,所以多了一些有索引操作的方法,如下图所示:

//1.创建一个ArrayList集合对象(有序、有索引、可以重复)
List<String> list = new ArrayList<>();
list.add("蜘蛛精");
list.add("至尊宝");
list.add("至尊宝");
list.add("牛夫人"); 
System.out.println(list); //[蜘蛛精, 至尊宝, 至尊宝, 牛夫人]

//2.public void add(int index, E element): 在某个索引位置插入元素
list.add(2, "紫霞仙子");
System.out.println(list); //[蜘蛛精, 至尊宝, 紫霞仙子, 至尊宝, 牛夫人]

//3.public E remove(int index): 根据索引删除元素, 返回被删除的元素
System.out.println(list.remove(2)); //紫霞仙子
System.out.println(list);//[蜘蛛精, 至尊宝, 至尊宝, 牛夫人]

//4.public E get(int index): 返回集合中指定位置的元素
System.out.println(list.get(3));

//5.public E set(int index, E e): 修改索引位置处的元素,修改后,会返回原数据
System.out.println(list.set(3,"牛魔王")); //牛夫人
System.out.println(list); //[蜘蛛精, 至尊宝, 至尊宝, 牛魔王]

3. List集合的遍历方式

        List集合相比于前面的Collection多了一种可以通过索引遍历的方式,所以List集合遍历方式一共有四种:

  • 普通for循环(只因为List有索引)

  • 迭代器

  • 增强for

  • Lambda表达式

List<String> list = new ArrayList<>();
list.add("蜘蛛精");
list.add("至尊宝");
list.add("糖宝宝");

//1.普通for循环
for(int i = 0; i< list.size(); i++){
    //i = 0, 1, 2
    String e = list.get(i);
    System.out.println(e);
}

//2.增强for遍历
for(String s : list){
    System.out.println(s);
}

//3.迭代器遍历
Iterator<String> it = list.iterator();
while(it.hasNext()){
    String s = it.next();
    System.out.println(s);
}

//4.lambda表达式遍历
list.forEach(s->System.out.println(s));

4. 遍历集合案例

        首先,我们得写一个电影类,用来描述每一步电影应该有哪些信息。

public class Movie{
    private String name; //电影名称
    private double score; //评分
    private String actor; //演员
    //无参数构造方法
    public Movie(){}
    //全参数构造方法
    public Movie(String name, double score, String actor){
        this.name=name;
        this.score=score;
        this.actor=actor;
    }
    //...get、set、toString()方法自己补上..
}

        接着,再创建一个测试类,完成上面的需求  

public class Test{
    public static void main(String[] args){
        Collection<Movie> movies = new ArrayList<>();
        movies.add(new MOvie("《肖申克的救赎》", 9.7, "罗宾斯"));
        movies.add(new MOvie("《霸王别姬》", 9.6, "张国荣、张丰毅"));
        movies.add(new MOvie("《阿甘正传》", 9.5, "汤姆汉克斯"));
        
        for(Movie movie : movies){
            System.out.println("电影名:" + movie.getName());
            System.out.println("评分:" + movie.getScore());
            System.out.println("主演:" + movie.getActor());
        }
    }
}

         以上代码的内存原理如下图所示:当往集合中存对象时,实际上存储的是对象的地址值

5.  ArrayList底层的原理

        ArrayList集合底层是基于数组结构实现的,也就是说当你往集合容器中存储元素时,底层本质上是往数组中存储元素。 特点如下:

        我们知道数组的长度是固定的,但是集合的长度是可变的,这是怎么做到的呢?原理如下:

        数组扩容,并不是在原数组上扩容(原数组是不可以扩容的),底层是创建一个新数组,然后把原数组中的元素全部复制到新数组中去。

6.  LinkedList底层原理

        LinkedList底层是链表结构,链表结构是由一个一个的节点组成,一个节点由数据值、下一个元素的地址组成。如下图所示

        假如,现在要在B节点和D节点中间插入一个元素,只需要把B节点指向D节点的地址断掉,重新指向新的节点地址就可以了。如下图所示:

        假如,现在想要把D节点删除,只需要让C节点指向E节点的地址,然后把D节点指向E节点的地址断掉。此时D节点就会变成垃圾,会把垃圾回收器清理掉。

        上面的链表是单向链表,它的方向是从头节点指向尾节点的,只能从左往右查找元素,这样查询效率比较慢;还有一种链表叫做双向链表,不光可以从做往右找,还可以从右往左找。如下图所示:

7. LinkedList集合新增对头尾进行操作的方法

        LinkedList集合是基于双向链表实现了,所以相对于ArrayList新增了一些可以针对头尾进行操作的方法,如下图示所示:

8. LinkedList集合的应用场景

(1)队列结构

        队列结构类似排队的流程。元素从上端入队列,从下端出队列。(先进先出,后进后出)

        入队列可以调用LinkedList集合的addLast方法,出队列可以调用removeFirst()方法.

//1.创建一个队列:先进先出、后进后出
LinkedList<String> queue = new LinkedList<>();
//入对列
queue.addLast("第1号人");
queue.addLast("第2号人");
queue.addLast("第3号人");
queue.addLast("第4号人");
System.out.println(queue);

//出队列
System.out.println(queue.removeFirst());	//第4号人
System.out.println(queue.removeFirst());	//第3号人
System.out.println(queue.removeFirst());	//第2号人
System.out.println(queue.removeFirst());	//第1号人

(2)栈结构     

栈结构可以看做是一个上端开头,下端闭口的弹夹的形状。元素永远是上端进,也从上端出,先进入的元素会压在最底下。(先进后出,后进先出)

//1.创建一个栈对象
LinkedList<String> stack = new ArrayList<>();
//压栈(push) 等价于 addFirst()
stack.push("第1颗子弹");
stack.push("第2颗子弹");
stack.push("第3颗子弹");
stack.push("第4颗子弹");
System.out.println(stack); //[第4颗子弹, 第3颗子弹, 第2颗子弹,第1颗子弹]

//弹栈(pop) 等价于 removeFirst()
System.out.println(statck.pop()); //第4颗子弹
System.out.println(statck.pop()); //第3颗子弹
System.out.println(statck.pop()); //第2颗子弹
System.out.println(statck.pop()); //第1颗子弹

//弹栈完了,集合中就没有元素了
System.out.println(list); //[]

  • 16
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值