Java集合进阶(一)

一、Collection

集合类的特点:提供一种存储空间可变的存储模型,存储的数据容量可以随时发生改变。

1. 概述

Collection 集合是单例集合的顶层接口,它表示一组对象,这些对象也称为 Collection 的元素。JDK 不提供此接口的任何直接实现,它提供更具体的子接口(如 Set 和 List)实现。

如何创建 Collection 集合的对象?
① 采用多态的方式;
② 具体的实现类是 ArrayList。

//Test.java

package com.an;

import java.util.ArrayList;
import java.util.Collection;

public class Test {
    
    
    public static void main(String[] args) {
    
    
        Collection<String> c = new ArrayList<String>();
        c.add("I");
        c.add("love");
        c.add("you");
        System.out.println(c); //[I, love, you]
    }
}

2. 常用方法

在这里插入图片描述

快捷键 Alt + 7 打开一个窗口,能够看到类的所有信息!

3. 集合遍历

Iterator:迭代器,集合的专用遍历方式。
迭代器是通过集合的 Iterator() 方法得到的,所以我们说它是依赖于集合而存在的。

Iterator 中的常用方法:
① next(),返回迭代中的下一个元素;
② hasNext(),如果迭代具有更多元素,则返回 true

//Test.java

package com.an;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

public class Test {
    
    
    public static void main(String[] args) {
    
    
        Collection<String> c = new ArrayList<String>();
        c.add("I");
        c.add("love");
        c.add("you");
        Iterator<String> it = c.iterator();
        while (it.hasNext()) {
    
    
            String s = it.next();
            System.out.println(s);
        }
    }
}

在这里插入图片描述

集合遍历步骤:
① 通过集合对象获取迭代器对象;
② 通过迭代器对象的 hasNext() 方法判断后面是否还有元素;
③ 通过迭代器对象的 next() 方法获取下一个元素。

4. 案例

需求:创建一个存储学生对象的集合,存储 3 个学生对象,使用程序实现在控制台遍历该集合。
思路:
① 定义学生类;
② 创建 Collection 集合对象;
③ 创建学生对象;
④ 把学生添加到集合;
⑤ 遍历集合(迭代器方式)。

//Student.java

package com.an;

public class Student {
    
    
    private String name;
    private int age;

    public Student() {
    
    
    }

    public Student(String name, int age) {
    
    
        this.name = name;
        this.age = age;
    }

    public String getName() {
    
    
        return name;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }

    public int getAge() {
    
    
        return age;
    }

    public void setAge(int age) {
    
    
        this.age = age;
    }

    @Override
    public String toString() {
    
    
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

//Test.java

package com.an;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

public class Test {
    
    
    public static void main(String[] args) {
    
    
        Student s1 = new Student("张三", 12);
        Student s2 = new Student("李四", 24);
        Student s3 = new Student("王五", 19);
        Collection<Student> c = new ArrayList<Student>();
        c.add(s1);
        c.add(s2);
        c.add(s3);
        Iterator<Student> it = c.iterator();
        while (it.hasNext()) {
    
    
            Student s = it.next();
            System.out.println(s);
        }
    }
}

在这里插入图片描述

二、List

1. 概述

List 集合是有序集合,用户可以精确控制列表中每个元素的插入位置,用户可以通过整数索引访问元素,并搜索列表中的元素,与 Set 集合不同,列表通常允许重复的元素。

List 集合特点:
① 有序:存储和取出的元素顺序一致;
② 可重复:存储的元素可以重复。

List<String> list = new ArrayList<String>();
list.add("I");
list.add("love");
list.add("you");
list.add("love");
System.out.println(list); //[I, love, you, love]

2. 特有方法

在这里插入图片描述

List 集合的遍历是有两种方式的:

//方式一,采用迭代器遍历
Iterator<String> it = list.iterator();
while (it.hasNext()) {
    
    
    Student s = it.next();
    System.out.println(s);
}

//方式二,用for循环遍历
for (int i = 0; i < list.size; i++) {
    
    
    String s = list.get(i);
    System.out.println(s);
}

3. 并发修改异常

并发修改异常的出现场景:
给出一个集合,遍历该集合,得到每一个元素,看看有没有 “world” 这个元素,如果有,就添加一个 “javaee” 元素。
并发修改异常产生原因:迭代器遍历过程中,通过集合对象修改了集合中元素的长度,造成了迭代器获取元素中判断预期修改值和实际修改值不一致!

这时候我们只能用 for 循环进行遍历,不能使用迭代器遍历,因为在给集合添加元素的时候,迭代器内部会进行一个判断,如果预期修改值和实际修改值不一致,就会抛出并发异常,throw new ConcurrentModificationException()。

//正确应使用for循环遍历
for (int i = 0; i < list.size(); i++) {
    
    
    String s = list.get(i);
    if (s.equals("world")) {
    
    
        list.add("javaee");
    }
}

也就是说,如果我们所做的改动会影响到集合的长度,那么使用迭代器遍历集合时就会产生并发修改异常,如果长度未变则不会抛出异常!

4. 列表迭代器

ListIterator:列表迭代器。

特点:
(1)通过 List 集合的 listIterator() 方法得到,所以它是 List 集合特有的迭代器;
(2)用于允许程序员沿任一方向遍历列表的列表迭代器,在迭代期间修改列表,并获取列表中迭代器的当前位置。

常用方法:
① next(),返回迭代中的下一个元素;
② hasNext(),如果迭代具有更多元素,则返回 true;
③ previous(),返回列表中的上一个元素;
④ hasPrevious(),如果此列表迭代器在相反方向遍历列表时具有更多元素,则返回 true;
⑤ add(e),将指定的元素插入列表。

ListIterator<String> lit  = l.listIterator();
while (lit.hasPrevious()) {
    
    
    String s = lit.previous();
    System.out.println(s);
}

迭代器的指针默认在最左边,所以直接使用逆向遍历是没有元素的,需要先使用正向遍历,反向才能输出,逆向遍历了解即可!

还记得我们上面的并发修改异常,不能用 Iterator 迭代器遍历添加元素,会抛出异常。接下来的 ListIterator 列表迭代器可以帮我们解决这个问题,也就是说,它是可以通过迭代器直接给列表添加元素的。

ListIterator<String> lit = list.listiterator();
while (lit.hasNext()) {
    
    
    String s = lit.next();
    if (s.equals("world")) {
    
    
        lit.add("javaee");
    }
}
System.out.println(list);

不会抛出并发修改异常,因为它的底层最终会把实际修改值赋值给预期修改值!

5. 增强 for 循环

增强 for:简化数组和 Collection 集合的遍历。

① 实现 Iterator 接口的类允许其对象成为增强型 for 语句的目标;
② 它是 JDK5 之后出现的,其内部原理是一个 Iterator 迭代器。

List<String> list  = new ArrayList<String>();
list.add("My");
list.add("beautiful");
list.add("baby");
for (String s : list) {
    
    
    System.out.println(s);
}

以下是一个案例,List 集合存储学生对象并遍历,这里学生类与上面的相同不变,所以只展示测试类。

//Test.java

package com.an;

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

public class Test {
    
    
    public static void main(String[] args) {
    
    
        Student s1 = new Student("刘德华", 60);
        Student s2 = new Student("张学友", 58);
        Student s3 = new Student("李易峰", 37);
        List<Student> list  = new ArrayList<Student>();
        list.add(s1);
        list.add(s2);
        list.add(s3);
        for (Student s : list) {
    
    
            System.out.println(s);
        }
    }
}

在这里插入图片描述
List 集合的遍历有三种方式,增强 for 是最方便的遍历方式,如果在遍历过程中要使用索引,那么我们就用普通的 for 循环即可!

6. 数据结构

数据结构是计算机存储、组织数据的方式,是指相互之间存在一种或多种特定关系的数据元素的集合。精心选择的数据结构可以带来更高的运行或者存储效率。

6.1 栈和队列

① 栈是一种数据先进后出的模型。数据进入栈模型的过程称为进栈,数据离开栈模型的过程称为出栈。
在这里插入图片描述

② 队列是一种数据先进先出的模型。数据从后端进入队列模型的过程称为入队列,数据从前端离开队列模型的过程称为出队列。
在这里插入图片描述

6.2 数组和链表

① 数组是一种查询快,增删慢的模型。查询数据通过索引定位,查询任意数据耗时相同,查询效率高;删除数据时,要将原始数据删除,同时后面的每个数据前移,删除效率低;添加数据时,先将添加位置后的每个数据后移,再添加元素,添加效率极低。

在这里插入图片描述

② 链表是一种增删快、查询慢的模型。链表可以通过修改下一结点的地址,来实现数据的增加和删除操作,速度较快;但是想要查询某一数据,它是要从头(head)开始查询的,显然查询效率很低。

在这里插入图片描述

存储一个数据 A 保存在地址 11 的位置,再存储一个数据 C 保存在地址 37 的位置,再存储一个数据 D 保存在地址 96 的位置,如下图:

在这里插入图片描述

head 是头结点表示开始,^ 是结点指向空地址表示结束!

在数据 AC 之间添加一个数据 B,保存在地址 54 位置,则数据 B 对应的下一个数据地址指向数据 C,数据 A 对应的下一个数据地址指向数据 B,如下图:

在这里插入图片描述
删除操作同理,若要删除数据 BD 之间的数据 C,可以让数据 B 对应的下一个数据地址指向数据 D,再删除数据 C 即可。

7. List 子类特点

List 集合常用子类:ArrayList,LinkedList。

① ArrayList,底层数据结构是数组,查询快,增删慢;
② LinkedList,底层数据结构是链表,查询慢,增删快。

//Test.java

package com.an;

import java.util.ArrayList;
import java.util.LinkedList;

public class Test {
    
    
    public static void main(String[] args) {
    
    
        ArrayList<String> list  = new ArrayList<String>();
        list.add("s1");
        list.add("s2");
        list.add("s3");
        for (String s : list) {
    
    
            System.out.println(s);
        }

        LinkedList<String> li  = new LinkedList<String>();
        li.add("S1");
        li.add("S2");
        li.add("S3");
        for (String s : li) {
    
    
            System.out.println(s);
        }
    }
}

7.1 LinkedList

LinkedList 集合的特有功能:

在这里插入图片描述

//Test.java

package com.an;

import java.util.LinkedList;

public class Test {
    
    
    public static void main(String[] args) {
    
    

        LinkedList<String> li  = new LinkedList<String>();
        li.add("S1");
        li.add("S2");
        li.add("S3");
        li.addFirst("what");
        li.addLast("www");
        System.out.println(li);
        System.out.println(li.getFirst());
        li.remove("S1");
        System.out.println(li);
        li.set(3, "hh");
        System.out.println(li);
    }
}

在这里插入图片描述

你可能会有疑问,这些方法能对列表的开头和结尾实施操作,那如果想操作中间部分怎么办呢?
不要忘了 LinkedList 可是 List 的一个子类,我们这里仅仅讲的是 LinkedList 的特有方法,想操作中间部分直接用 and、remove 和 set 等方法就行了,父类的方法子类都是可以直接拿来用的。

猜你喜欢

转载自blog.csdn.net/m0_52861684/article/details/129398452