发布于2026-07-10 阅读(0)
扫一扫,手机访问
先来说一个很多人容易忽略的细节:Collections.checkedList() 不会去修改你原来的列表,它只是返回一个包装器。原列表该怎么用还怎么用——如果你不把所有写操作都引导到这个包装引用上,那类型安全就是一句空话。换句话说,它只管自己这扇门,不管旁边的窗户有没有关好。

Collections.checkedList() 不能直接“加固”已有列表说白了,它不修改原列表,而是返回一个新包装器对象——原列表依然裸奔。任何绕过包装器的写入(比如直接调用原列表的 add())都不会被检查。你必须确保所有写操作都走这个包装后的引用,否则类型安全形同虚设。
new ArrayList() )本身没有泛型运行时约束,JVM 允许 rawList.add(new Integer(42))。Collections.checkedList(rawList, String.class) 返回的是 CheckedList 实例,它在 add()、set()、addAll() 等方法里插入前做 instanceof 检查。最稳妥的方式是:从创建起就只暴露包装后的引用,原列表要么私有化,要么直接丢掉。
ListsafeList = Collections.checkedList( new ArrayList<>(), String.class);
ArrayList raw = new ArrayList<>(); List safe = Collections.checkedList(raw, String.class); —— 因为 raw 依然可用,等于留了个后门。Class 参数必须和你要的类型严格匹配;比如用 String.class 包装 ArrayList 不会报错,但后续 add("hello")` 一调用马上抛 ClassCastException。get()、size() 等读操作没有额外开销,写操作只多一次类型判断,性能影响可以忽略不计。它只拦截那些明确可能引入非法对象的写方法,并不是什么都管。
add()、set()、addAll()、retainAll()(注意 removeAll() 呢?它其实不检查要移除的元素是否匹配,它只防止因操作意外注入非法类型)。get()、iterator()、listIterator() 返回的迭代器本身——不过这些迭代器上的 set() 和 add() 方法会被检查。toArray() 不检查,但返回的数组类型由运行时实际内容决定。要是原列表被污染了(比如有人绕过包装器塞了一个 Integer),那 toArray(String[].class) 会直接抛出 ArrayStoreException。这个东西不是编译期类型系统的一部分,它是在运行时补一层防御——所以它只能防“写入时类型不符”,防不了所有类型错误。
safeList.add((Object)42)(因为泛型在运行时已经擦除了),但到了运行时 checkedList 会立刻抛 ClassCastException。Field.setAccessible(true) 直接改底层数组),也防不了序列化/反序列化污染。Collections.emptyList()),checkedList() 会包装成功,但所有写操作都会立即失败——这有时是故意为之,用来构建带类型校验的只读契约。说到底,真正起作用的前提是:你把包装后的引用当作唯一的入口来使用。一旦原始引用泄露,或者混用原始列表,这个防护就形同虚设。它解决的是“不小心写错类型”的问题,不是“恶意破坏”的问题。
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
8