云计算百科
云计算领域专业知识百科平台

JavaWeb 30 天入门:第八天 ——Java 集合框架详解

        在前七天的学习中,我们掌握了 Java 基础语法、面向对象特性、异常处理等核心知识。今天我们将深入学习Java 集合框架(Collection Framework)—— 这是 Java 提供的一套用于存储和操作多个数据的工具类。在 JavaWeb 开发中,集合框架被广泛用于处理批量数据(如查询结果集、表单提交的多条数据等),掌握它能极大提高数据处理效率。

为什么需要集合框架?

数组作为 Java 中最基础的数据容器,存在诸多局限性:

  • 长度固定,无法动态扩展
  • 只能存储相同类型的元素
  • 缺乏常用操作(如添加、删除、查找等)的内置方法

集合框架正是为解决这些问题而设计的,它具有:

  • 动态扩展:可以根据需要自动调整大小
  • 丰富的操作:内置添加、删除、查找、排序等方法
  • 多数据结构:提供多种数据结构(列表、集合、映射等)满足不同需求
  • 泛型支持:编译时类型检查,避免类型转换错误

集合框架体系结构

Java 集合框架主要分为两大体系:

  • Collection 接口:存储单个元素的集合

    • List:有序、可重复的集合(如ArrayList、LinkedList)
    • Set:无序、不可重复的集合(如HashSet、TreeSet)
    • Queue:队列(先进先出,如LinkedList、PriorityQueue)
  • Map 接口:存储键值对(key-value)的集合(如HashMap、TreeMap)

  • 体系结构简图:

    java.util
    ├─ Collection(接口)
    │ ├─ List(接口)
    │ │ ├─ ArrayList(实现类)
    │ │ ├─ LinkedList(实现类)
    │ │ └─ Vector(实现类,线程安全)
    │ │
    │ ├─ Set(接口)
    │ │ ├─ HashSet(实现类)
    │ │ ├─ TreeSet(实现类,有序)
    │ │ └─ LinkedHashSet(实现类,保持插入顺序)
    │ │
    │ └─ Queue(接口)
    │ └─ LinkedList(实现类)

    └─ Map(接口)
    ├─ HashMap(实现类)
    ├─ TreeMap(实现类,按键排序)
    ├─ LinkedHashMap(实现类,保持插入顺序)
    └─ Hashtable(实现类,线程安全)

    泛型:集合的类型安全保障

    在 JDK 5 之前,集合可以存储任意类型的对象,取出时需要强制类型转换,容易出现ClassCastException。泛型(Generic)解决了这个问题,它允许在定义集合时指定元素类型:

    // 定义泛型集合(只能存储String类型)
    List<String> stringList = new ArrayList<String>();
    // JDK 7+可以简化为
    List<String> stringList = new ArrayList<>();

    泛型的优势:

    • 编译时类型检查,避免类型错误
    • 无需强制类型转换,代码更简洁
    • 提高代码的可读性和可维护性

    List 接口:有序可重复的集合

    List接口是 Collection 的子接口,具有以下特点:

    • 元素有序(按插入顺序排列)
    • 元素可重复
    • 可以通过索引访问元素(类似数组)

    1. ArrayList:基于动态数组的实现

    ArrayList是最常用的 List 实现类,底层使用动态数组存储元素:

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

    public class ArrayListDemo {
    public static void main(String[] args) {
    // 创建ArrayList(存储String类型)
    List<String> fruits = new ArrayList<>();

    // 1. 添加元素
    fruits.add("苹果");
    fruits.add("香蕉");
    fruits.add("橙子");
    fruits.add(1, "葡萄"); // 在索引1处插入元素
    System.out.println("添加后:" + fruits); // [苹果, 葡萄, 香蕉, 橙子]

    // 2. 获取元素
    String first = fruits.get(0);
    System.out.println("第一个元素:" + first); // 苹果

    // 3. 修改元素
    fruits.set(2, "西瓜");
    System.out.println("修改后:" + fruits); // [苹果, 葡萄, 西瓜, 橙子]

    // 4. 删除元素
    fruits.remove(3); // 按索引删除
    fruits.remove("葡萄"); // 按元素删除
    System.out.println("删除后:" + fruits); // [苹果, 西瓜]

    // 5. 遍历元素
    System.out.println("遍历元素:");
    // 方式1:for循环
    for (int i = 0; i < fruits.size(); i++) {
    System.out.println(fruits.get(i));
    }

    // 方式2:增强for循环
    for (String fruit : fruits) {
    System.out.println(fruit);
    }

    // 6. 其他常用方法
    System.out.println("是否包含苹果:" + fruits.contains("苹果")); // true
    System.out.println("集合大小:" + fruits.size()); // 2
    System.out.println("是否为空:" + fruits.isEmpty()); // false

    // 清空集合
    fruits.clear();
    System.out.println("清空后:" + fruits); // []
    }
    }

    ArrayList的特点:

    • 查找和修改快(通过索引直接访问)
    • 添加和删除慢(需要移动大量元素)
    • 初始容量为 10,当元素满时自动扩容为原来的 1.5 倍

    2. LinkedList:基于双向链表的实现

    LinkedList底层使用双向链表存储元素,适合频繁添加和删除的场景:

    import java.util.LinkedList;
    import java.util.List;

    public class LinkedListDemo {
    public static void main(String[] args) {
    List<Integer> numbers = new LinkedList<>();

    // 添加元素
    numbers.add(10);
    numbers.add(20);
    numbers.addFirst(5); // 添加到头部
    numbers.addLast(30); // 添加到尾部
    System.out.println("LinkedList内容:" + numbers); // [5, 10, 20, 30]

    // 链表特有的方法
    System.out.println("第一个元素:" + numbers.getFirst()); // 5
    System.out.println("最后一个元素:" + numbers.getLast()); // 30

    numbers.removeFirst(); // 删除头部元素
    numbers.removeLast(); // 删除尾部元素
    System.out.println("操作后:" + numbers); // [10, 20]

    // 作为队列使用(先进先出)
    LinkedList<String> queue = new LinkedList<>();
    queue.offer("A"); // 入队
    queue.offer("B");
    queue.offer("C");
    System.out.println("出队元素:" + queue.poll()); // A
    System.out.println("队列剩余:" + queue); // [B, C]
    }
    }

    LinkedList的特点:

    • 添加和删除快(只需修改指针指向)
    • 查找和修改慢(需要从头遍历)
    • 实现了 Queue 接口,可作为队列使用

    3. ArrayList vs LinkedList 如何选择?

    场景推荐使用原因
    频繁查询和修改 ArrayList 基于数组,索引访问效率高
    频繁添加和删除 LinkedList 基于链表,操作节点效率高
    存储大量数据 ArrayList 内存占用更紧凑
    需要作为队列使用 LinkedList 实现了 Queue 接口

    Set 接口:无序不可重复的集合

    Set接口是 Collection 的子接口,具有以下特点:

    • 元素无序(存储顺序和取出顺序可能不同)
    • 元素不可重复(通过equals()方法判断)
    • 没有索引,不能通过索引访问元素

    1. HashSet:基于哈希表的实现

    HashSet是最常用的 Set 实现类,底层基于哈希表(HashMap)实现:

    import java.util.HashSet;
    import java.util.Set;

    public class HashSetDemo {
    public static void main(String[] args) {
    Set<String> cities = new HashSet<>();

    // 添加元素(自动去重)
    cities.add("北京");
    cities.add("上海");
    cities.add("广州");
    cities.add("北京"); // 重复元素,添加失败
    System.out.println("HashSet内容:" + cities); // [上海, 广州, 北京](顺序不确定)

    // 删除元素
    cities.remove("广州");
    System.out.println("删除后:" + cities); // [上海, 北京]

    // 遍历元素(没有索引,不能用普通for循环)
    System.out.println("遍历元素:");
    for (String city : cities) {
    System.out.println(city);
    }

    // 其他常用方法
    System.out.println("是否包含上海:" + cities.contains("上海")); // true
    System.out.println("集合大小:" + cities.size()); // 2
    }
    }

    HashSet去重原理:

  • 计算元素的哈希值(hashCode()方法)
  • 若哈希值不同,直接存储
  • 若哈希值相同,通过equals()方法判断是否真的相同
  • 两者都相同则视为重复元素,不存储
  • 注意:自定义类存储到 HashSet 时,必须重写hashCode()和equals()方法,否则无法正确去重:

    import java.util.Objects;

    public class Student {
    private String id;
    private String name;

    // 构造方法、getter、setter省略

    // 重写hashCode和equals
    @Override
    public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;
    Student student = (Student) o;
    return Objects.equals(id, student.id); // 按学号判断是否相同
    }

    @Override
    public int hashCode() {
    return Objects.hash(id); // 基于学号计算哈希值
    }
    }

    2. TreeSet:有序的 Set 集合

    TreeSet底层基于红黑树实现,能够对元素进行排序:

    import java.util.Set;
    import java.util.TreeSet;

    public class TreeSetDemo {
    public static void main(String[] args) {
    // 存储整数(自动排序)
    Set<Integer> nums = new TreeSet<>();
    nums.add(30);
    nums.add(10);
    nums.add(20);
    nums.add(10); // 重复元素,不存储
    System.out.println("排序后的整数:" + nums); // [10, 20, 30]

    // 存储字符串(按自然顺序排序)
    Set<String> words = new TreeSet<>();
    words.add("banana");
    words.add("apple");
    words.add("cherry");
    System.out.println("排序后的字符串:" + words); // [apple, banana, cherry]
    }
    }

    TreeSet排序方式:

    • 自然排序:元素实现Comparable接口,重写compareTo()方法
    • 定制排序:创建 TreeSet 时传入Comparator比较器

    实例:自定义对象的 TreeSet 排序

    import java.util.Set;
    import java.util.TreeSet;

    // 学生类实现Comparable接口
    class Student implements Comparable<Student> {
    private String name;
    private int age;

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

    // 按年龄排序
    @Override
    public int compareTo(Student o) {
    return this.age – o.age; // 正数:当前对象大;负数:当前对象小;0:相等
    }

    @Override
    public String toString() {
    return name + "(" + age + ")";
    }
    }

    public class TreeSetCustomSort {
    public static void main(String[] args) {
    Set<Student> students = new TreeSet<>();
    students.add(new Student("张三", 20));
    students.add(new Student("李四", 18));
    students.add(new Student("王五", 22));

    System.out.println("按年龄排序:" + students); // [李四(18), 张三(20), 王五(22)]
    }
    }

    Map 接口:键值对集合

    Map接口用于存储键值对(key-value)映射,具有以下特点:

    • 键(key)不可重复,值(value)可以重复
    • 每个键对应一个值,通过键可以快速查找值
    • 常用实现类:HashMap、TreeMap、LinkedHashMap

    1. HashMap:基于哈希表的实现

    HashMap是最常用的 Map 实现类,底层基于哈希表实现:

    import java.util.HashMap;
    import java.util.Map;
    import java.util.Set;

    public class HashMapDemo {
    public static void main(String[] args) {
    // 创建HashMap(键:String,值:Integer)
    Map<String, Integer> scores = new HashMap<>();

    // 1. 添加键值对
    scores.put("张三", 90);
    scores.put("李四", 85);
    scores.put("王五", 95);
    scores.put("张三", 92); // 键相同,覆盖值
    System.out.println("HashMap内容:" + scores); // {李四=85, 张三=92, 王五=95}(顺序不确定)

    // 2. 获取值
    int zhangSanScore = scores.get("张三");
    System.out.println("张三的分数:" + zhangSanScore); // 92

    // 3. 判断是否包含键/值
    System.out.println("是否包含李四:" + scores.containsKey("李四")); // true
    System.out.println("是否包含100分:" + scores.containsValue(100)); // false

    // 4. 删除键值对
    scores.remove("王五");
    System.out.println("删除后:" + scores); // {李四=85, 张三=92}

    // 5. 遍历Map
    System.out.println("遍历键:");
    Set<String> keys = scores.keySet(); // 获取所有键
    for (String key : keys) {
    System.out.println(key + ":" + scores.get(key));
    }

    System.out.println("遍历键值对:");
    Set<Map.Entry<String, Integer>> entries = scores.entrySet(); // 获取所有键值对
    for (Map.Entry<String, Integer> entry : entries) {
    System.out.println(entry.getKey() + ":" + entry.getValue());
    }

    // 6. 其他常用方法
    System.out.println("集合大小:" + scores.size()); // 2
    scores.clear(); // 清空集合
    System.out.println("清空后:" + scores); // {}
    }
    }

    HashMap的特点:

    • 查找、添加、删除效率高(基于哈希表)
    • 键无序(存储顺序和取出顺序可能不同)
    • 键可以为 null(但只能有一个 null 键)
    • JDK 8 + 中,当链表长度超过 8 时,会转为红黑树提高性能

    2. TreeMap:有序的 Map 集合

    TreeMap底层基于红黑树实现,能够按键进行排序:

    import java.util.Map;
    import java.util.TreeMap;

    public class TreeMapDemo {
    public static void main(String[] args) {
    // TreeMap会自动按键排序
    Map<String, String> dictionary = new TreeMap<>();
    dictionary.put("banana", "香蕉");
    dictionary.put("apple", "苹果");
    dictionary.put("cherry", "樱桃");

    System.out.println("按键排序:" + dictionary);
    // 输出:{apple=苹果, banana=香蕉, cherry=樱桃}
    }
    }

    3. LinkedHashMap:保持插入顺序的 Map

    LinkedHashMap是HashMap的子类,能够保持键值对的插入顺序:

    import java.util.LinkedHashMap;
    import java.util.Map;

    public class LinkedHashMapDemo {
    public static void main(String[] args) {
    Map<String, Integer> map = new LinkedHashMap<>();
    map.put("张三", 20);
    map.put("李四", 18);
    map.put("王五", 22);

    // 输出顺序与插入顺序一致
    System.out.println("LinkedHashMap内容:" + map);
    // 输出:{张三=20, 李四=18, 王五=22}
    }
    }

    集合工具类:Collections

    java.util.Collections类提供了大量静态方法,用于操作集合:

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

    public class CollectionsDemo {
    public static void main(String[] args) {
    List<Integer> list = new ArrayList<>();
    list.add(3);
    list.add(1);
    list.add(2);

    // 排序
    Collections.sort(list);
    System.out.println("排序后:" + list); // [1, 2, 3]

    // 反转
    Collections.reverse(list);
    System.out.println("反转后:" + list); // [3, 2, 1]

    // 查找最大值
    int max = Collections.max(list);
    System.out.println("最大值:" + max); // 3

    // 填充
    Collections.fill(list, 0);
    System.out.println("填充后:" + list); // [0, 0, 0]

    // 线程安全的集合
    List<Integer> synchronizedList = Collections.synchronizedList(new ArrayList<>());
    }
    }

    集合框架在 JavaWeb 中的应用

    在 JavaWeb 开发中,集合框架的应用非常广泛:

  • 处理表单提交的批量数据:

    // Servlet中获取多选框数据
    String[] hobbies = request.getParameterValues("hobby");
    List<String> hobbyList = Arrays.asList(hobbies); // 数组转集合

  • 存储数据库查询结果:

    // 查询所有用户
    List<User> userList = new ArrayList<>();
    while (rs.next()) {
    User user = new User();
    user.setId(rs.getInt("id"));
    user.setName(rs.getString("name"));
    userList.add(user);
    }
    request.setAttribute("users", userList); // 存入请求域

  • 处理 JSON 数据:
    前后端交互的 JSON 数组通常会转换为 Java 集合进行处理

  • 总结与实践

    知识点回顾

  • 集合框架体系:

    • Collection:存储单个元素(List 有序可重复,Set 无序不可重复)
    • Map:存储键值对(key-value)
  • 常用实现类:

    • List:ArrayList(数组实现,查询快)、LinkedList(链表实现,增删快)
    • Set:HashSet(哈希表,去重)、TreeSet(红黑树,排序)
    • Map:HashMap(哈希表,常用)、TreeMap(排序)、LinkedHashMap(保持顺序)
  • 泛型:定义集合时指定元素类型,确保类型安全

  • Collections 工具类:提供排序、查找等集合操作方法

  • 实践任务

  • 学生成绩管理系统:

    • 创建Student类(包含姓名、学号、成绩)
    • 使用ArrayList存储多个学生对象
    • 实现功能:添加学生、删除学生、修改成绩、按成绩排序、查询平均分
    • 使用HashMap统计各分数段的学生数量(如 90-100 分、80-89 分等)
  • 去重与排序练习:

    • 定义一个字符串数组:{"apple", "banana", "apple", "orange", "banana"}
    • 使用HashSet对数组去重
    • 将去重后的结果转换为TreeSet,实现按字母顺序排序
    • 输出最终结果
  • 思考:在处理大量数据时,ArrayList和LinkedList哪个性能更好?为什么?

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » JavaWeb 30 天入门:第八天 ——Java 集合框架详解
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!