You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

XML反序列化后访问Sublist抛出ConcurrentModificationException问题

XStream序列化ArrayList子列表:Java6 vs Java7差异解析

你遇到的问题核心在于Java6和Java7中ArrayList.subList()的实现差异,以及XStream对不同版本子列表类的序列化行为不同。先回顾下你的场景:使用XStream 1.4.4序列化ArrayList的子列表,Java7反序列化后迭代抛出ConcurrentModificationException,但Java6正常,最终通过将子列表转为新ArrayList解决了问题。

你的测试代码

import java.util.ArrayList;
import java.util.List;
import com.thoughtworks.xstream.XStream;

public class TestClass {
    public static void main(String[] args) {
        List<String> someList = new ArrayList<String>();
        someList.add("String1");
        someList.add("String2");
        someList.add("String3");
        
        List<String> someSubList = someList.subList(0, 2);
        for (String string : someSubList) {
            System.out.println(string);
        }
        
        System.out.println("=====================================");
        XStream xstr = new XStream();
        String subListXML = xstr.toXML(someSubList);
        System.out.println(subListXML);
        
        System.out.println("=====================================");
        @SuppressWarnings("unchecked")
        List<String> subList = (List<String>) xstr.fromXML(subListXML);
        for (String string : subList) { // 这里Java7抛出异常
            System.out.println(string);
        }
    }
}

Java7抛出的异常

Exception in thread "main" java.util.ConcurrentModificationException
 at java.util.ArrayList$SubList.checkForComodification(ArrayList.java:1169)
 at java.util.ArrayList$SubList.listIterator(ArrayList.java:1049)
 at java.util.AbstractList.listIterator(AbstractList.java:299)
 at java.util.ArrayList$SubList.iterator(ArrayList.java:1045)
 at com.test.TestClass.main(TestClass.java:36)

不同Java版本生成的XML结构

Java7生成的XML

<java.util.ArrayList_-SubList>
 <parent class="list">
 <string>String1</string>
 <string>String2</string>
 <string>String3</string>
 </parent>
 <parentOffset>0</parentOffset>
 <offset>0</offset>
 <size>2</size>
 <outer-class reference="../parent"/>
</java.util.ArrayList_-SubList>

Java6生成的XML

<java.util.RandomAccessSubList>
 <l class="list">
 <string>String1</string>
 <string>String2</string>
 <string>String3</string>
 </l>
 <offset>0</offset>
 <size>2</size>
 <expectedModCount>3</expectedModCount>
</java.util.RandomAccessSubList>

问题解答

1. 为什么Java6中反序列化子列表后迭代不会触发异常?

这不是“创建子列表被视为结构性修改”的问题,而是Java6和Java7的子列表实现类不同,XStream的序列化行为也有差异:

  • Java6中,ArrayList.subList()返回的是java.util.RandomAccessSubList,这个类自己维护了一个expectedModCount字段,用来跟踪原列表的修改次数。
  • XStream序列化RandomAccessSubList时,会把expectedModCount字段写入XML(你提供的Java6 XML里能看到这个字段值为3,对应原列表添加3个元素后的修改次数)。
  • 反序列化时,XStream会重建原列表(调用add方法添加三个元素),此时原列表的modCount会递增到3;同时RandomAccessSubList的expectedModCount被还原为3。当你迭代子列表时,checkForComodification()检查原列表的modCount和子列表的expectedModCount相等,所以不会抛出异常。

2. 为什么Java7中的异常在XML反序列化后而非之前抛出?

ConcurrentModificationException是在迭代子列表时触发的修改检查,而非反序列化过程:

  • Java7中,ArrayList.subList()返回的是ArrayList$SubList内部类,它的checkForComodification()方法会比较原列表的modCount和自己的modCount(这个值在子列表创建时从原列表复制)。
  • 反序列化过程只是创建ArrayList$SubList对象并设置它的字段(比如parent、offset等),但不会触发修改检查——因为此时还没有遍历列表。
  • 当你尝试迭代反序列化后的子列表时,调用iterator()方法会触发listIterator(),进而调用checkForComodification()。此时反序列化出来的原列表modCount是3(XStream添加元素时递增的),但SubList自己的modCount是默认初始值0(XStream没有序列化这个字段,因为它不是公开字段),两者不匹配,所以抛出异常。

你的解决方案为什么有效?

当你用new ArrayList<String>(someList.subList(0, 2))创建新列表时,本质是把原列表的子列表元素复制到一个全新的ArrayList中,不再和原列表有引用关联。XStream序列化这个新列表时,只会保存元素内容,反序列化后得到的是独立的ArrayList,自然不会有修改检查的问题,生成的XML也更简洁。

内容的提问来源于stack exchange,提问作者Heena Jain

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 06:33:01