当前位置:首页 > 文章列表 > 文章 > java教程 > Java reversed 视图上的修改会不会影响原集合

Java reversed 视图上的修改会不会影响原集合

来源:17golang原创 2026-10-05 22:21:04 0浏览 收藏

会影响,但要先分清“影响”的方向:Java 21 的 List.reversed() 返回的是反向有序视图,不是把元素重新复制一份。对支持修改的视图执行写操作,变化会写回原集合;原集合的后续变化也会反映到视图。若底层集合本身只读,视图同样不能写。

官方地址:https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/SequencedCollection.html

要点速览
  • reversed() 改变的是 encounter order,不是集合存储。
  • 可变 ArrayList 的反向视图通常会把 set、删除和两端插入写回原列表。
  • 需要完全隔离修改时,显式创建 new ArrayList(list.reversed()),不要把视图当副本。

reversed 是视图,先别把它当成副本

JEP 431 为有序集合补上了统一的双向操作。List.reversed() 的返回值仍然指向同一组元素,只是把首尾、前驱和后继的语义反过来。因此遍历 source.reversed() 时看到的是从末尾到开头的顺序,元素对象本身并没有被复制。

这个区别会直接影响代码审查:如果方法只需要倒序读取,视图很方便;如果方法可能调用 set、remove 或 addFirst,就必须把它当作原集合的另一条写入口。

Java List reversed 反向视图与原集合共享元素存储的关系说明图
图1:结构说明图,展示原集合、反向视图和双向变化的关系;这不是运行截图。

可变 ArrayList 上的修改会怎样写回

下面的例子把“视图顺序”和“底层顺序”同时打印出来。注意 addFirst 是以反向视图的第一位为参照,所以它对应原列表的末尾插入。

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

public class ReversedViewDemo {
    public static void main(String[] args) {
        List source = new ArrayList(List.of("A", "B", "C"));
        List reverse = source.reversed();

        // 视图的第一个元素对应原列表的最后一个元素。
        reverse.set(0, "C2");
        // 在反向视图中删除第二项,实际删除原列表中的 B。
        reverse.remove(1);
        // 反向视图的首端对应原列表的尾端。
        reverse.addFirst("D");

        System.out.println("source=" + source);
        System.out.println("reverse=" + reverse);
    }
}
source=[A, C2, D]
reverse=[D, C2, A]

这里的三个动作都作用于同一份数据:set(0) 改了原列表的最后一个槽位,remove(1) 删除了原列表中的中间元素,addFirst 则把元素加到原列表末端。视图只是把这些位置换算成反向坐标。

只读集合的 reversed 仍然只读

对比可变 ArrayList、只读 List.of 和显式复制三种写入边界。
图2:边界说明图,对比可变视图、只读视图和复制列表的写入结果;不是运行截图。

“视图会写回”有一个前提:实现允许修改。对 List.of 或 List.copyOf 得到的只读列表调用 reversed(),可以正常遍历,但写操作仍会抛出 UnsupportedOperationException。这不是 reversed 特有的限制,而是底层集合的写权限被视图继承了。

import java.util.List;

class ReadOnlyReversed {
    static void tryWrite() {
        List source = List.of("A", "B", "C");
        List reverse = source.reversed();

        // 只读底层集合不能通过反向视图修改。
        try {
            reverse.set(0, "C2");
        } catch (UnsupportedOperationException ex) {
            // 业务代码可在这里转成明确的参数错误或改用复制方案。
            System.out.println("read-only view");
        }
    }
}

另外,视图不是并发快照。若一个线程遍历视图,另一个线程直接修改底层 ArrayList,仍需遵守集合的线程安全规则,不能因为有了 reversed() 就得到同步或快照语义。

需要隔离修改时,显式复制才安全

如果目标是“拿一份倒序数据,后续怎么改都不影响原集合”,写法应当明确表达复制意图:

List source = new ArrayList(List.of("A", "B", "C"));
// 复制反向遍历结果,后续写入不会回到 source。
List working = new ArrayList(source.reversed());
working.set(0, "C2");

可以用下面这张清单做选择:

目标推荐写法结果
只倒序读取list.reversed()零额外元素副本,保留视图关系
倒序修改原列表在可变列表的视图上操作修改写回底层集合
倒序后独立编辑new ArrayList(list.reversed())编辑副本,不回写原列表

常见问题

reversed 会把原 List 的顺序永久反转吗?

不会。它提供反向观察方式;只有通过可变视图执行插入、删除或替换时,才会改变元素内容或数量,原列表本身的遍历顺序仍按原方向表达。

Collections.reverse 和 List.reversed 有什么区别?

Collections.reverse(list) 是对原列表原地换序;list.reversed() 返回反向视图,原列表不因“创建视图”而换序。

为什么 reversed 后调用 add 可能失败?

因为底层列表可能是 List.of、List.copyOf 或其他不可修改实现。先判断业务是否需要写入,再决定使用可变列表或显式复制。

判断这类代码最稳妥的顺序是:先看返回值是不是 view,再看底层集合是否可变,最后确认调用方需要的是共享修改还是独立副本。这样既能利用 Java 21 的倒序 API,也不会把一次看似普通的 set 误当成局部修改。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
tapaim试玩入口怎么理解?TapTap页面、应用本体与账号服务边界tapaim试玩入口怎么理解?TapTap页面、应用本体与账号服务边界
上一篇
tapaim试玩入口怎么理解?TapTap页面、应用本体与账号服务边界
Go nil channel 为什么会让 select 分支持久禁用
下一篇
Go nil channel 为什么会让 select 分支持久禁用
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    343次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    403次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    403次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    362次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    184次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议 和 隐私政策
返回登录
  • 重置密码