文章目录
- 一、Collection
 - 1. 概述
 - 2. 常用方法
 - 3. 集合遍历
 - 4. 案例
 
- 二、List
 - 1. 概述
 - 2. 特有方法
 - 3. 并发修改异常
 - 4. 列表迭代器
 - 5. 增强 for 循环
 - 6. 数据结构
 - 6.1 栈和队列
 - 6.2 数组和链表
 
- 7. List 子类特点
 - 7.1 LinkedList
 
一、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 等方法就行了,父类的方法子类都是可以直接拿来用的。



















