Java集合概述

Java集合框架是Java语言的核心组件之一,它提供了一套性能优良、使用灵活的数据结构,用于存储和操作数据集合。本节我们将深入探讨集合框架的几个关键部分,并通过代码示例展示其在实际业务场景中的应用。

#### 1. 集合框架概述
Java集合框架主要包括以下几类接口与实现:

- **List**:有序集合,允许重复元素,主要实现有ArrayList、LinkedList和Vector。
- **Set**:无序集合,不允许重复元素,主要实现有HashSet、LinkedHashSet和TreeSet。
- **Map**:键值对映射,键必须唯一,主要实现有HashMap、LinkedHashMap、TreeMap等。
- **Queue**:队列接口,遵循先进先出(FIFO)原则,实现包括LinkedList、PriorityQueue等。

#### 2. List接口与实现
- **ArrayList**:基于动态数组实现,支持随机访问,插入删除效率较低。
- **LinkedList**:基于双向链表实现,插入删除效率较高,但随机访问效率低。**案例:员工信息管理**
```java

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

class Employee {
    String name;
    int id;

    // Constructor, getters, and setters
}

public class EmployeeManager {
    public static void main(String[] args) {
        List<Employee> employees = new ArrayList<>();
        employees.add(new Employee("Alice", 1));
        employees.add(new Employee("Bob", 2));
        
        // 随机访问
        System.out.println(employees.get(0).getName());
        
        // 添加与删除
        employees.add(new Employee("Charlie", 3));
        employees.remove(1);
    }
}


```

#### 3. Set接口与实现
- **HashSet**:基于哈希表实现,不保证顺序,查找效率高。
- **TreeSet**:基于红黑树实现,自然排序或自定义比较器排序。**案例:去重与排序**
```java

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

public class UniqueSortedList {
    public static void main(String[] args) {
        Set<Integer> numbers = new HashSet<>();
        numbers.add(5);
        numbers.add(7);
        numbers.add(5); // 重复元素,不会被添加
        System.out.println(numbers); // 输出:[5, 7]
        
        TreeSet<String> sortedNames = new TreeSet<>();
        sortedNames.add("Charlie");
        sortedNames.add("Alice");
        sortedNames.add("Bob");
        System.out.println(sortedNames); // 输出:[Alice, Bob, Charlie]
    }
}


```

#### 4. Map接口与实现
- **HashMap**:基于哈希表实现,键值对无序,插入、获取效率高。
- **TreeMap**:基于红黑树实现,键自然排序或自定义比较器排序。**案例:学生分数记录**
```java

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

class Student {
    String name;
    // Constructor, getters, and setters
}

public class ScoreRecord {
    public static void main(String[] args) {
        Map<Student, Integer> scores = new HashMap<>();
        Student alice = new Student("Alice");
        Student bob = new Student("Bob");
        
        scores.put(alice, 90);
        scores.put(bob, 85);
        
        System.out.println(scores.get(alice)); // 输出:90
    }
}


```

#### 5. 泛型的重要性
泛型提供了编译时类型安全检查,避免了运行时的ClassCastException。

```java

List<String> stringList = new ArrayList<>(); // 使用泛型指定只能存放String类型
stringList.add("Hello"); // 正确
// stringList.add(123); // 编译错误,因为123不是String类型


```

#### 6. 迭代器与比较器
- **迭代器(Iterator)**:遍历集合元素的统一方式。
- **比较器(Comparator)**:用于自定义排序规则。

通过以上内容的学习,我们不仅掌握了Java集合框架的基本概念和主要接口的使用,还通过实例体会到了它们在解决实际问题中的灵活性和高效性。集合框架是Java开发者不可或缺的工具箱,熟练运用它们能极大提升开发效率和代码质量。

在Java中,`List`接口是继承自`Collection`接口的一个子接口,它专门用于处理具有顺序特性的集合。与`Set`不同,`List`中的元素可以重复,并且每个元素都有一个明确的位置(即索引)。下面,我将以ArrayList、LinkedList和Vector这三种常见的List实现为例,通过简化的示例代码来详细说明它们的使用方法和特性。

### 1. ArrayList

**特点**:基于动态数组实现,支持随机访问,插入和删除效率较低(特别是在列表开头或中间位置)。```java

import java.util.ArrayList;

public class ArrayListExample {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        
        // 添加元素
        list.add("Apple");
        list.add("Banana");
        list.add("Cherry");
        
        // 访问元素
        System.out.println("First element: " + list.get(0));
        
        // 插入元素
        list.add(1, "Orange"); // 在索引1处插入
        
        // 删除元素
        list.remove("Banana");
        
        // 遍历
        for (String fruit : list) {
            System.out.println(fruit);
        }
    }
}


```

### 2. LinkedList

**特点**:基于双向链表实现,插入和删除操作效率较高(尤其是在列表的开始和结尾),但随机访问较慢。```java

import java.util.LinkedList;

public class LinkedListExample {
    public static void main(String[] args) {
        LinkedList<String> list = new LinkedList<>();
        
        // 添加元素
        list.add("Apple");
        list.addLast("Banana"); // 也可以使用addLast在末尾添加
        list.addFirst("Cherry"); // 或者在开头添加
        
        // 访问元素
        System.out.println("First element: " + list.getFirst());
        
        // 插入元素
        list.add(1, "Orange"); // 索引插入,效率不如直接的addFirst或addLast
        
        // 删除元素
        list.removeFirst(); // 快速移除第一个元素
        
        // 遍历
        for (String fruit : list) {
            System.out.println(fruit);
        }
    }
}


```

### 3. Vector

**特点**:早期Java版本中的线程安全版ArrayList,现在由于同步开销较大,不推荐在新代码中使用。但在需要线程安全的场景下仍可考虑。```java

import java.util.Vector;

public class VectorExample {
    public static void main(String[] args) {
        Vector<String> vector = new Vector<>();
        
        // 添加元素
        vector.addElement("Apple"); // 或使用add方法
        vector.add("Banana");
        vector.add("Cherry");
        
        // 访问元素
        System.out.println("First element: " + vector.firstElement());
        
        // 插入元素
        vector.insertElementAt("Orange", 1); // 或使用add(index, element)
        
        // 删除元素
        vector.removeElement("Banana"); // 或使用remove方法
        
        // 遍历
        for (String fruit : vector) {
            System.out.println(fruit);
        }
    }
}


```

以上代码示例展示了如何使用这三种List实现进行基本的集合操作,如添加、访问、插入、删除和遍历元素。每种实现都有其特定的应用场景,选择时应根据实际需求考虑性能和线程安全等因素。

下面我会通过代码示例分别展示`List`允许重复元素和`Set`不允许重复元素的特点。

### List 允许重复元素```java

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

public class ListAllowsDuplicates {
    public static void main(String[] args) {
        List<String> fruits = new ArrayList<>();

        fruits.add("Apple");
        fruits.add("Banana");
        fruits.add("Apple"); // 允许重复添加

        System.out.println("List with duplicates:");
        for (String fruit : fruits) {
            System.out.println(fruit);
        }
    }
}


```

在这个例子中,我们向`ArrayList`(`List`的实现之一)中添加了两次"Apple"。运行这段代码,你会看到输出中包含了两个"Apple",证明了`List`确实允许元素重复。

### Set 不允许重复元素```java

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

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

        fruits.add("Apple");
        fruits.add("Banana");
        fruits.add("Apple"); // 尝试重复添加

        System.out.println("Set without duplicates:");
        for (String fruit : fruits) {
            System.out.println(fruit);
        }
    }
}


```

在这个例子中,我们尝试向`HashSet`(`Set`的实现之一)中添加两次"Apple"。当你运行这段代码时,输出中只会显示一次"Apple",这是因为`Set`的特性是不允许包含重复的元素,所以第二次添加的"Apple"被忽略了。

这两个示例清晰地展示了`List`和`Set`在处理重复元素上的根本区别。`List`适合于需要维护元素插入顺序和/或允许元素重复的场景,而`Set`则适用于需要确保所有元素唯一的情况。

为了进一步阐述ListSet的不同应用场景,让我们通过一些扩展的例子来更深入地理解它们的特性和用途。

### List 特性扩展示例:排序和按索引操作```java

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

public class ListSortExample {
    public static void main(String[] args) {
        // 创建并填充一个ArrayList
        List<Integer> numbers = new ArrayList<>();
        numbers.add(5);
        numbers.add(3);
        numbers.add(7);
        numbers.add(2);
        numbers.add(4);
        
        // 输出原始列表
        System.out.println("Original List: " + numbers);
        
        // 对列表进行排序
        Collections.sort(numbers);
        
        // 输出排序后的列表
        System.out.println("Sorted List: " + numbers);
        
        // 按索引访问和修改
        int thirdElement = numbers.get(2); // 获取第3个元素
        System.out.println("Third Element: " + thirdElement);
        numbers.set(2, 10); // 将第3个元素替换为10
        
        // 输出修改后的列表
        System.out.println("Modified List: " + numbers);
    }
}


```

这个示例展示了`List`的几个重要特性:你可以轻松对列表进行排序(使用`Collections.sort()`),并且可以通过索引来访问和修改指定位置的元素,这是`Set`无法提供的功能。

### Set 特性扩展示例:去重和交集、并集操作`

``java
i

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

public class SetOperationsExample {
    public static void main(String[] args) {
        // 创建并填充两个HashSet
        Set<Integer> set1 = new HashSet<>();
        set1.add(1);
        set1.add(2);
        set1.add(3);
        set1.add(4);
        
        Set<Integer> set2 = new HashSet<>();
        set2.add(3);
        set2.add(4);
        set2.add(5);
        set2.add(6);
        
        // 输出原始集合
        System.out.println("Set 1: " + set1);
        System.out.println("Set 2: " + set2);
        
        // 求两个集合的并集
        Set<Integer> union = new HashSet<>(set1);
        union.addAll(set2);
        System.out.println("Union: " + union);
        
        // 求两个集合的交集
        Set<Integer> intersection = new HashSet<>(set1);
        intersection.retainAll(set2);
        System.out.println("Intersection: " + intersection);
    }
}


```

这个示例演示了`Set`在处理数据去重和执行集合运算方面的优势。我们可以很容易地通过`addAll`方法得到两个集合的并集,通过`retainAll`方法找到它们的交集,这对于需要处理数据唯一性和集合间关系的场景非常有用。

当我们讨论将`List`和`Set`的概念与MySQL数据库结合起来时,我们实际上是在探讨如何在数据库层面模拟这些集合类型的行为。MySQL本身并不直接提供名为“List”或“Set”的数据类型,但它有类似的数据结构和特性,可以用来实现类似的功能。以下是如何在MySQL中利用数据表模拟这些集合类型的简单示例。

### 模拟List(有序,允许重复元素) - 使用普通表

假设我们要存储一个用户购买的商品列表,其中商品可以重复购买。

```sql

CREATE TABLE UserPurchases (
    UserID INT,
    ProductID INT,
    PurchaseTime TIMESTAMP,
    PRIMARY KEY(UserID, ProductID),
    FOREIGN KEY(ProductID) REFERENCES Products(ProductID)
);

INSERT INTO UserPurchases (UserID, ProductID, PurchaseTime)
VALUES (1, 101, '2024-04-01 10:00:00'),
       (1, 102, '2024-04-02 11:30:00'),
       (1, 101, '2024-04-03 14:45:00'); -- 同一商品重复购买


```

在这个例子中,`UserPurchases`表模拟了一个用户购买记录的列表,每条记录包含用户ID、商品ID和购买时间。通过允许同一用户ID和商品ID的多条记录存在,我们模拟了`List`的特性:有序(通过`PurchaseTime`字段间接实现)且允许重复元素。

### 模拟Set(无序,不允许重复元素) - 使用唯一索引

如果我们想在数据库中存储一个用户喜欢的商品集合,且每个商品只出现一次(类似于`Set`),我们可以这样做:

```sql

CREATE TABLE UserFavorites (
    UserID INT,
    ProductID INT,
    PRIMARY KEY(UserID, ProductID),
    UNIQUE INDEX(UserID, ProductID), -- 确保每种商品对用户来说是唯一的
    FOREIGN KEY(ProductID) REFERENCES Products(ProductID)
);

INSERT INTO UserFavorites (UserID, ProductID)
VALUES (1, 101),
       (1, 102),
       (1, 101); -- 尝试插入重复项,但会被数据库拒绝


```

在这里,通过定义一个包含`UserID`和`ProductID`的复合主键,并为这对字段添加唯一索引,我们确保了每个用户对于每种商品只能有一条记录,从而模拟了`Set`的无序且不允许重复元素的特性。尝试插入重复的商品ID将会失败,因为这违反了唯一性约束。

### 总结

虽然MySQL没有直接对应`List`或`Set`的数据类型,但通过合理设计表结构和使用索引约束,我们可以有效地模拟这些集合的特性。在实际应用中,选择合适的数据模型和约束条件对于满足特定业务需求至关重要。

让我们继续以MySQL数据库为基础,创建一个简单的表并插入10条数据,然后通过SQL查询来展示如何操作这些数据,类似于我们之前讨论的`List`和`Set`概念。

### 创建表与插入数据

假设我们要创建一个`Students`表来存储学生的姓名和成绩,这里我们不设定成绩必须唯一,以便模拟`List`允许重复值的特性。

```sql

CREATE TABLE Students (
    ID INT AUTO_INCREMENT PRIMARY KEY,
    Name VARCHAR(50) NOT NULL,
    Score INT
);
-- 插入10条数据,包括一些重复的成绩
INSERT INTO Students (Name, Score)
VALUES ('Alice', 85),
       ('Bob', 90),
       ('Charlie', 90), -- 重复的成绩
       ('David', 88),
       ('Eva', 78),
       ('Frank', 85), -- 另一个重复的成绩
       ('Grace', 92),
       ('Henry', 80),
       ('Ivy', 85), -- 再次重复
       ('Jack', 95);


```

### 查询与操作

#### 查询所有学生信息

```sql

SELECT * FROM Students;


```

这相当于从`List`中获取所有元素。

#### 查询成绩大于等于90的学生

```sql

SELECT * FROM Students WHERE Score >= 90;


```

这类似于从`List`中筛选出满足特定条件的元素。

#### 删除特定学生(比如删除ID为5的学生)

```sql

DELETE FROM Students WHERE ID = 5;


```

这模拟了从`List`中移除一个元素的操作。

#### 更新学生信息(比如将ID为3的学生的成绩改为88)

```sql

UPDATE Students SET Score = 88 WHERE ID = 3;


```

这类似于在`List`中修改某个元素的值。

### 结论

通过上述操作,我们不仅在MySQL中创建了一个表并插入了数据,还展示了如何通过SQL命令对这些数据进行查询和操作,模拟了在内存中使用`List`进行数据管理的一些基本操作。虽然数据库操作涉及更多的细节,如事务管理和数据持久化,但其核心理念与我们在Java集合框架中使用的数据结构操作是相通的。数据库提供了更强大的数据管理和检索能力,同时保证了数据的一致性和持久性。

让我们继续上面的MySQL数据库例子,并加入Java代码来展示如何通过JDBC(Java Database Connectivity)连接到MySQL数据库,执行前面提到的SQL操作。请注意,为了简化示例,这里不包含异常处理和资源管理的最佳实践,实际应用中应该使用try-with-resources语句或者在finally块中关闭资源。

首先,确保你已经安装了MySQL数据库,并创建了相应的数据库以及上面提到的`Students`表。

### Java代码示例```java

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class StudentDatabaseExample {

    private static final String URL = "jdbc:mysql://localhost:3306/your_database_name";
    private static final String USER = "your_username";
    private static final String PASSWORD = "your_password";

    public static void main(String[] args) {
        try {
            // 1. 加载驱动并建立连接
            Class.forName("com.mysql.cj.jdbc.Driver");
            Connection conn = DriverManager.getConnection(URL, USER, PASSWORD);

            // 2. 插入数据示例(这里假设数据已手动插入,不重复此步骤)
            
            // 3. 查询所有学生信息
            Statement stmt = conn.createStatement();
            ResultSet rs = stmt.executeQuery("SELECT * FROM Students");
            while (rs.next()) {
                System.out.println("ID: " + rs.getInt("ID") + ", Name: " + rs.getString("Name") + ", Score: " + rs.getInt("Score"));
            }
            rs.close();
            stmt.close();

            // 4. 查询成绩大于等于90的学生
            PreparedStatement pstmt = conn.prepareStatement("SELECT * FROM Students WHERE Score >= ?");
            pstmt.setInt(1, 90);
            rs = pstmt.executeQuery();
            System.out.println("\nScores >= 90:");
            while (rs.next()) {
                System.out.println(rs.getString("Name") + " - Score: " + rs.getInt("Score"));
            }
            rs.close();
            pstmt.close();

            // 5. 更新学生信息示例(例如,将ID为3的学生的成绩改为88,这里先检查是否存在)
            pstmt = conn.prepareStatement("UPDATE Students SET Score = ? WHERE ID = ?");
            pstmt.setInt(1, 88);
            pstmt.setInt(2, 3);
            int rowsAffected = pstmt.executeUpdate();
            if (rowsAffected > 0) {
                System.out.println("\nStudent with ID 3 updated successfully.");
            } else {
                System.out.println("\nNo student found with ID 3 to update.");
            }
            pstmt.close();

            // 6. 删除学生信息示例(例如,删除ID为5的学生,这里先检查是否存在)
            pstmt = conn.prepareStatement("DELETE FROM Students WHERE ID = ?");
            pstmt.setInt(1, 5);
            rowsAffected = pstmt.executeUpdate();
            if (rowsAffected > 0) {
                System.out.println("\nStudent with ID 5 deleted successfully.");
            } else {
                System.out.println("\nNo student found with ID 5 to delete.");
            }
            pstmt.close();

            conn.close();
        } catch (ClassNotFoundException | SQLException e) {
            e.printStackTrace();
        }
    }
}


```

这段Java代码通过JDBC连接到MySQL数据库,执行了查询、更新和删除等操作,这些操作对应了之前讨论的SQL命令,展示了如何在Java程序中与MySQL数据库交互,实现了对数据的CRUD(创建、读取、更新、删除)操作,类似于在内存中操作集合对象。请确保替换`your_database_name`、`your_username`和`your_password`为你的实际数据库信息。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值