ZetCode

Java Collections.checkedList 方法

上次修改时间:2025 年 4 月 20 日

Collections.checkedList 方法是 Java 集合框架的一部分。它返回指定列表的动态类型安全视图。这有助于在运行时捕获类型不匹配,而不是允许它们破坏集合。

类型安全视图在处理遗留代码或异构集合时特别有用。它们提供运行时类型检查,补充了 Java 的编译时泛型。该方法是在 Java 5 中引入的。

Collections.checkedList 概述

Collections.checkedList 包装现有列表以提供运行时类型检查。任何尝试插入错误类型元素的行为都将抛出 ClassCastException。这有助于维护集合的完整性。

该方法的签名是 static <E> List<E> checkedList(List<E> list, Class<E> type)。它接受一个列表和一个代表元素类型的 Class 对象。返回的列表强制执行此类型约束。

checkedList 的基本用法

此示例演示了 Collections.checkedList 的基本用法。我们创建一个常规的 ArrayList,然后用类型安全视图包装它。该示例显示了有效和无效的操作。

BasicCheckedList.java
package com.zetcode;

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

public class BasicCheckedList {

    public static void main(String[] args) {
        
        List<String> names = new ArrayList<>();
        names.add("John");
        names.add("Lucy");
        
        // Create type-safe view
        List<String> checkedNames = 
            Collections.checkedList(names, String.class);
        
        // Valid operation
        checkedNames.add("Bob");
        System.out.println("Names: " + checkedNames);
        
        try {
            // Invalid operation - will throw ClassCastException
            List rawList = checkedNames;
            rawList.add(42); // Adding Integer to String list
        } catch (ClassCastException e) {
            System.out.println("Caught: " + e.getMessage());
        }
    }
}

此代码创建了 String 列表的类型安全视图。我们首先成功添加有效的 String 元素。然后,我们演示了 checked list 如何通过尝试添加 Integer 来捕获类型不匹配。

输出显示有效操作正常完成,而无效操作抛出异常。这有助于在开发期间识别类型安全问题。

使用遗留代码

当与不使用泛型的遗留代码交互时,checkedList 特别有用。此示例展示了它如何在这些场景中防止类型污染。

LegacyCodeIntegration.java
package com.zetcode;

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

public class LegacyCodeIntegration {

    public static void main(String[] args) {
        
        // Modern typed list
        List<Integer> numbers = new ArrayList<>();
        numbers.add(1);
        numbers.add(2);
        
        // Create type-safe view
        List<Integer> checkedNumbers = 
            Collections.checkedList(numbers, Integer.class);
        
        // Pass to legacy method
        legacyMethod(checkedNumbers);
        
        System.out.println("Numbers after legacy call: " + numbers);
    }
    
    // Legacy method without generics
    @SuppressWarnings({"rawtypes", "unchecked"})
    private static void legacyMethod(List list) {
        // Attempt to add wrong type
        list.add("Not a number"); // Will throw ClassCastException
    }
}

此示例演示了在将类型化集合传递给遗留代码时保护它的方法。legacyMethod 不使用泛型,通常可以插入任何类型。checked list 可以防止这种情况。

输出显示即使与非泛型代码交互,类型安全性也得到了维护。这使得 checkedList 对于逐步现代化遗留系统非常有用。

Checked List 与自定义对象

Collections.checkedList 与自定义对象一样适用于内置类型。此示例演示了将其与自定义类一起使用。

CustomObjectCheckedList.java
package com.zetcode;

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

class Product {
    private String name;
    
    public Product(String name) {
        this.name = name;
    }
    
    @Override
    public String toString() {
        return name;
    }
}

public class CustomObjectCheckedList {

    public static void main(String[] args) {
        
        List<Product> products = new ArrayList<>();
        products.add(new Product("Laptop"));
        
        // Create type-safe view
        List<Product> checkedProducts = 
            Collections.checkedList(products, Product.class);
        
        // Valid addition
        checkedProducts.add(new Product("Phone"));
        System.out.println("Products: " + checkedProducts);
        
        try {
            // Invalid addition
            checkedProducts.add("Not a product"); // String instead of Product
        } catch (ClassCastException e) {
            System.out.println("Caught: " + e.getMessage());
        }
    }
}

此示例创建了一个 Product 对象的 checked list。我们展示了有效添加 Product 实例和无效尝试添加 String 的情况。类型安全性在运行时强制执行。

输出表明只有正确的 Product 对象才能添加到 checked list。即使使用自定义类型,这也能维护集合的完整性。

性能注意事项

虽然 checkedList 提供了宝贵的类型安全性,但它也具有性能影响。此示例演示了衡量使用 checked 集合的开销。

CheckedListPerformance.java
package com.zetcode;

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

public class CheckedListPerformance {

    public static void main(String[] args) {
        
        final int COUNT = 1000000;
        List<Integer> regularList = new ArrayList<>();
        List<Integer> checkedList = 
            Collections.checkedList(new ArrayList<>(), Integer.class);
        
        // Test regular list
        long start = System.currentTimeMillis();
        for (int i = 0; i < COUNT; i++) {
            regularList.add(i);
        }
        long regularTime = System.currentTimeMillis() - start;
        
        // Test checked list
        start = System.currentTimeMillis();
        for (int i = 0; i < COUNT; i++) {
            checkedList.add(i);
        }
        long checkedTime = System.currentTimeMillis() - start;
        
        System.out.println("Regular list time: " + regularTime + "ms");
        System.out.println("Checked list time: " + checkedTime + "ms");
        System.out.println("Overhead: " + 
            (100.0 * (checkedTime - regularTime) / regularTime + "%");
    }
}

此代码比较了在添加元素时普通列表和 checked 列表的性能。checked 列表在每次插入时都会执行类型检查,这增加了开销。确切的开销因 JVM 实现而异。

输出显示了相对的性能差异。在大多数应用程序中,安全优势超过了小的性能成本。但是,在性能关键部分,应考虑这一点。

Checked List 与 Null 值

Collections.checkedList 特别处理 null 值。此示例演示了 null 在 checked 集合中的处理方式。

CheckedListWithNulls.java
package com.zetcode;

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

public class CheckedListWithNulls {

    public static void main(String[] args) {
        
        List<String> names = new ArrayList<>();
        List<String> checkedNames = 
            Collections.checkedList(names, String.class);
        
        // Adding null to checked list is allowed
        checkedNames.add(null);
        System.out.println("List with null: " + checkedNames);
        
        // Adding non-null values still checked
        checkedNames.add("Alice");
        System.out.println("List with values: " + checkedNames);
        
        try {
            // Still catches invalid types
            List rawList = checkedNames;
            rawList.add(42);
        } catch (ClassCastException e) {
            System.out.println("Caught: " + e.getMessage());
        }
    }
}

此示例显示 null 值可以添加到 checked list,而不管元素类型如何。类型检查仅适用于非 null 值。这与 Java 通常处理泛型中的 null 的方式一致。

输出表明,虽然允许使用 null,但仍会强制对实际值进行类型安全检查。当处理可能包含 null 的集合时,了解此行为很重要。

与其他集合方法的结合使用

Collections.checkedList 可以与其他集合实用方法结合使用。此示例展示了如何将其与 unmodifiableList 结合使用以实现最大安全性。

CombinedCollectionsUtilities.java
package com.zetcode;

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

public class CombinedCollectionsUtilities {

    public static void main(String[] args) {
        
        List<Double> prices = new ArrayList<>();
        prices.add(19.99);
        
        // Create type-safe and unmodifiable view
        List<Double> safePrices = Collections.unmodifiableList(
            Collections.checkedList(prices, Double.class));
        
        System.out.println("Initial list: " + safePrices);
        
        // Can modify through original reference
        prices.add(29.99);
        System.out.println("After original modification: " + safePrices);
        
        try {
            // Cannot modify through safe view
            safePrices.add(39.99);
        } catch (UnsupportedOperationException e) {
            System.out.println("Caught modification attempt: " + e.getMessage());
        }
        
        try {
            // Still type-checked
            List rawList = safePrices;
            rawList.add("Not a number");
        } catch (ClassCastException e) {
            System.out.println("Caught type violation: " + e.getMessage());
        }
    }
}

此示例结合了类型安全性和不可变性。我们首先创建一个 checked list,然后使其不可修改。结果是一个集合,它既是类型安全的,又不能通过其公共接口修改。

输出显示,修改仍然可以通过原始引用进行,但不能通过包装视图进行。在所有情况下都维护了类型安全性。这种组合对于 API 来说非常强大。

来源

Java Collections.checkedList 文档

在本文中,我们深入探讨了 Java 的 Collections.checkedList 方法。我们介绍了基本用法、遗留代码集成、性能、null 处理以及与其他实用程序的结合使用。此工具对于维护 Java 集合中的类型安全性非常有用。

作者

我叫 Jan Bodnar,是一位经验丰富的程序员,在编程领域拥有多年经验。我从 2007 年开始撰写编程文章,此后撰写了 1,400 多篇文章和八本电子书。凭借超过八年的教学经验,我致力于分享我的知识并帮助他人掌握编程概念。

列出所有Java教程