将Multimaps.synchronizedSortedSetMultimap转为TreeMultimap遇类型不匹配求助
嘿,这个问题我之前踩过坑!咱们先搞清楚为什么强制转换会失败:Multimaps.synchronizedSortedSetMultimap()返回的并不是TreeMultimap实例,而是一个SortedSetMultimap的同步包装类(可以理解为给原集合套了个线程安全的壳),这个包装类和TreeMultimap是平级的实现类,没有继承关系,所以强转肯定会抛ClassCastException。
下面给你两种常用的解决方案,看你具体场景选:
方案一:提前保留TreeMultimap的引用(推荐)
如果你的需求是既要TreeMultimap的特性,又要线程安全的同步访问,正确的姿势是先创建TreeMultimap,再给它套同步包装,而不是反过来。这样你可以直接持有底层TreeMultimap的引用,随时用它做TreeMultimap专属的操作:
// 1. 先创建原生的TreeMultimap实例 TreeMultimap<String, Integer> treeMultimap = TreeMultimap.create(); // 2. 再把它包装成线程安全的SortedSetMultimap SortedSetMultimap<String, Integer> syncMultimap = Multimaps.synchronizedSortedSetMultimap(treeMultimap); // 之后需要用TreeMultimap的时候,直接用treeMultimap就行 treeMultimap.put("a", 1); // 同步访问的时候用syncMultimap syncMultimap.put("b", 2);
方案二:从同步集合复制元素到新的TreeMultimap
如果已经有一个现成的同步SortedSetMultimap,现在必须得到TreeMultimap类型的实例,可以把同步集合里的所有元素复制到一个新的TreeMultimap中:
// 假设你已经有一个同步的SortedSetMultimap SortedSetMultimap<String, Integer> existingSyncMultimap = ...; // 复制所有元素到新的TreeMultimap TreeMultimap<String, Integer> newTreeMultimap = TreeMultimap.create(existingSyncMultimap);
⚠️ 注意:这个新的TreeMultimap是非同步的,如果需要线程安全,记得再用Multimaps.synchronizedSortedSetMultimap()包装一次。
为啥不能强转?
再啰嗦一句:Guava的同步包装器设计就是为了给任意SortedSetMultimap实现添加线程安全,它本身只是个“代理”,内部持有原集合,但自己的类型和原集合完全不同。比如你给TreeMultimap套同步壳,得到的是SynchronizedSortedSetMultimap类,这个类并没有继承TreeMultimap,所以强转根本行不通。
内容的提问来源于stack exchange,提问作者Jiew Meng

