Java ArrayList 怎么不可变化

小明吖_7545

小明吖_7545

2026-11-15

129人浏览

原创

要让 arraylist 不可变,最稳妥的做法是使用 collections.unmodifiablelist() 包装原列表。调用该方法会返回一个视图,任何试图修改该视图的操作都会抛出 unsupportedoperationexception。需要注意的是,如果原列表本身被外部持有并修改,这个“不可变”视图也会随之变化,因此必须确保原列表不再被其他代码访问。

Java ArrayList 怎么不可变化

如何防止外部通过原引用修改列表内容

仅仅使用 Collections.unmodifiableList() 只能防止通过返回的视图进行修改,如果调用者仍然持有原始 ArrayList 的引用,他们依然可以随意增删元素。要彻底实现不可变性,必须在封装时立即将原列表替换为一个新的、包含相同元素的独立副本,并将原引用设为私有或丢弃。

Java ArrayList 怎么不可变化

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

public class ImmutableExample {
    private final List<string> data;

    public ImmutableExample(List<string> input) {
        // 1. 创建副本,切断与原引用的联系
        List<string> copy = new ArrayList(input);
        // 2. 包装为不可变视图
        this.data = Collections.unmodifiableList(copy);
    }

    public List<string> getData() {
        return data;
    }

    public static void main(String[] args) {
        List<string> original = new ArrayList();
        original.add("A");
        original.add("B");

        ImmutableExample example = new ImmutableExample(original);

        // 尝试通过视图修改 -> 抛出异常
        try {
            example.getData().add("C");
        } catch (UnsupportedOperationException e) {
            System.out.println("视图修改失败: " + e.getMessage());
        }

        // 尝试通过原引用修改(如果原引用仍有效)
        // 注意:在上面的构造函数中,我们传入了original,
        // 但example内部使用的是copy,所以original的修改不会影响example
        original.add("C"); 
        System.out.println("Original size: " + original.size()); // 3
        System.out.println("Internal size: " + example.getData().size()); // 2
    }
}</string></string></string></string></string>

上述代码展示了标准的防御性拷贝模式。构造函数接收输入列表后,立即通过 new ArrayList(input) 创建副本。随后对副本进行包装。这样,即使外部的 original 列表后续被修改,内部的 data 也不会受到影响,因为两者在内存中已完全分离。

为什么直接返回 unmodifiableList 的结果是不安全的

如果在构造器中直接使用传入的列表进行包装,而不先创建副本,会导致数据泄露。这是因为 Collections.unmodifiableList() 返回的是一个动态视图,它始终指向底层的原始集合对象。只要原始集合存在且可被修改,这个视图就不是真正不可变的。

JavaScript 测试模式
JavaScript 测试模式

使用 Jest、Vitest 和 Testing Library 实施全面的测试策略,包括单元测试、集成测试和端到端测试,涵盖模拟、测试夹具和测试驱动开发。在编

下载

Java ArrayList 怎么不可变化

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

public class UnsafeImmutableExample {
    private final List<string> data;

    public UnsafeImmutableExample(List<string> input) {
        // 错误做法:直接包装原引用
        this.data = Collections.unmodifiableList(input);
    }

    public List<string> getData() {
        return data;
    }

    public static void main(String[] args) {
        List<string> externalRef = new ArrayList();
        externalRef.add("X");

        UnsafeImmutableExample example = new UnsafeImmutableExample(externalRef);

        // 虽然通过 example.getData() 无法修改
        // 但通过 externalRef 可以直接修改底层数据
        externalRef.add("Y");

        System.out.println(example.getData().get(1)); // 输出 Y
        // 这证明了所谓的“不可变”实际上是被动的,受外部控制
    }
}</string></string></string></string>

在这个不安全示例中,UnsafeImmutableExample 的构造函数直接将传入的 input 列表包装。当外部代码持有 externalRef 引用时,它可以绕过 getData() 的限制,直接向 externalRef 添加元素。由于 data 是 externalRef 的视图,这些更改会立即反映在 example 的内部状态中。这种设计违背了不可变性的初衷,使得对象的状态变得脆弱且不可预测。

基于程序中输入参数为空时的具体行为问题

当传入的输入列表为 null 时,Collections.unmodifiableList() 的行为取决于具体的实现版本和调用方式,但在标准 Java 库中,它通常允许传入 null 并返回一个空的不可变列表视图,或者在某些情况下抛出异常。更关键的是,如果我们在构造函数中先创建副本 new ArrayList(null),这会抛出 NullPointerException。因此,处理 null 输入是确保不可变对象健壮性的关键一步。

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

public class NullSafeImmutableExample {
    private final List<string> data;

    public NullSafeImmutableExample(List<string> input) {
        if (input == null) {
            // 方案一:返回空列表
            this.data = Collections.emptyList();
        } else {
            // 方案二:创建副本并包装
            this.data = Collections.unmodifiableList(new ArrayList(input));
        }
    }

    public List<string> getData() {
        return data;
    }

    public static void main(String[] args) {
        // 测试 null 输入
        NullSafeImmutableExample example1 = new NullSafeImmutableExample(null);
        System.out.println(example1.getData().isEmpty()); // true

        // 测试正常输入
        List<string> normalInput = new ArrayList();
        normalInput.add("Test");
        NullSafeImmutableExample example2 = new NullSafeImmutableExample(normalInput);
        System.out.println(example2.getData().get(0)); // Test
    }
}</string></string></string></string>

在处理 null 输入时,直接调用 new ArrayList(null) 会触发 NullPointerException。为了保持不可变对象的稳定性,应在构造函数入口处显式检查 null。如果输入为 null,可以选择返回一个预定义的 Collections.emptyList(),这是一个真正的单例不可变空列表,既安全又节省内存。如果输入非空,则继续执行副本创建和包装流程。这种处理方式确保了无论输入如何,内部状态始终处于一致且安全的不可变状态。

Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南

相关文章

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

java java arraylist

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
java
java

Java是一个通用术语,用于表示Java软件及其组件,包括“Java运行时环境 (JRE)”、“Java虚拟机 (JVM)”以及“插件”。php中文网还为大家带了Java相关下载资源、相关课程以及相关文章等内容,供大家免费下载使用。

2023.06.15

12637

6

java正则表达式语法
java正则表达式语法

java正则表达式语法是一种模式匹配工具,它非常有用,可以在处理文本和字符串时快速地查找、替换、验证和提取特定的模式和数据。本专题提供java正则表达式语法的相关文章、下载和专题,供大家免费下载体验。

2023.07.05

9742

9

java自学难吗
java自学难吗

Java自学并不难。Java语言相对于其他一些编程语言而言,有着较为简洁和易读的语法,本专题为大家提供java自学难吗相关的文章,大家可以免费体验。

2023.07.31

8272

8

java配置jdk环境变量
java配置jdk环境变量

Java是一种广泛使用的高级编程语言,用于开发各种类型的应用程序。为了能够在计算机上正确运行和编译Java代码,需要正确配置Java Development Kit(JDK)环境变量。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2023.08.01

1324

3

java保留两位小数
java保留两位小数

Java是一种广泛应用于编程领域的高级编程语言。在Java中,保留两位小数是指在进行数值计算或输出时,限制小数部分只有两位有效数字,并将多余的位数进行四舍五入或截取。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2023.08.02

1048

3

java基本数据类型
java基本数据类型

java基本数据类型有:1、byte;2、short;3、int;4、long;5、float;6、double;7、char;8、boolean。本专题为大家提供java基本数据类型的相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.02

1576

5

java有什么用
java有什么用

java可以开发应用程序、移动应用、Web应用、企业级应用、嵌入式系统等方面。本专题为大家提供java有什么用的相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.02

3309

5

java在线网站
java在线网站

Java在线网站是指提供Java编程学习、实践和交流平台的网络服务。近年来,随着Java语言在软件开发领域的广泛应用,越来越多的人对Java编程感兴趣,并希望能够通过在线网站来学习和提高自己的Java编程技能。php中文网给大家带来了相关的视频、教程以及文章,欢迎大家前来学习阅读和下载。

2023.08.03

20551

3

配置java环境变量
配置java环境变量

配置Java环境变量是为了让操作系统能够识别和使用Java的相关命令和功能。本专题为大家提供配置java环境变量相关文章,帮助大家解决问题。

2023.08.03

1435

8

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
dev.java 官方:Learn Java
dev.java 官方:Learn Java

共0课时 | 0人学习

Java JDBC数据库连接官方教程
Java JDBC数据库连接官方教程

共0课时 | 0人学习