作者PsMonkey (痞子军团团长)
看板Translate-CS
标题[翻译] Java Collection API 的怪事
时间Fri Mar 22 04:31:14 2013
原文网址:
http://www.javacodegeeks.com/2013/03/java-collections-api-quirks.html
译文网址:
http://blog.dontcareabout.us/2013/03/java-collection-api.html
感谢 tkcn 在 Java 技术上的协助。
BBS 版用 markdown 语法撰写
______________________________________________________________________
在提到 Java Collection API 时,我们会认为已经了解全部的东西了,
像是 [List]、[Set]、[Map]、[Iterable]、[Iterator]。
我们已经准备好 [补强 Java8 的 Collection API][enhance API]。
[List]:
http://docs.oracle.com/javase/7/docs/api/java/util/List.html
[Set]:
http://docs.oracle.com/javase/7/docs/api/java/util/Set.html
[Map]:
http://docs.oracle.com/javase/7/docs/api/java/util/Map.html
[Iterable]:
http://docs.oracle.com/javase/7/docs/api/java/lang/Iterable.html
[Iterator]:
http://docs.oracle.com/javase/7/docs/api/java/util/Iterator.html
[enhance API]:
http://cr.openjdk.java.net/~briangoetz/
lambda/collections-overview.html
但在那之後,每隔一段时间我们就会偶然发现这些奇怪的怪事,
来自於 JDK 深处、以及向下相容的遥远历史。
让我们来看一下这些不可修改(unmodifiable) 的 collection。
不可修改的 collection
-------------------
无论 collection 是否可以修改,都无法跟 collection API 作对应。
JDK 并没有 immutable 的 `List`、`Set`、`Collection` 的基础 type,
继承出来的就是 mutable 的 subtype。
所以下面这个 API 是不会出现在 JDK 当中的:
// Immutable part of the Collection API
public interface Collection {
boolean contains(Object o);
boolean containsAll(Collection<?> c);
boolean isEmpty();
int size();
Object[] toArray();
<T> T[] toArray(T[] array);
}
// Mutable part of the Collection API
public interface MutableCollection
extends Collection {
boolean add(E e);
boolean addAll(Collection<? extends E> c);
void clear();
boolean remove(Object o);
boolean removeAll(Collection<?> c);
boolean retainAll(Collection<?> c);
}
有几个可能的原因解释为甚麽早期 Java 不这样实作。
最可能的原因是:不把 mutable 特性视为一个功能,
值得在 type 阶层当中占据一个 type。
所以,伴随而来的 [Collections] 这个 helper class 就会有一些好用的 method,
像是 `unmodifiableList()`、`unmodifiableSet()`、
`unmodifiableCollection()`...... 等等。
但是在使用不可修改的 collection 时要注意,
[JavaDoc 中有一个非常奇怪的事情][quirk in JavaDoc]:
回传的 collection 并没有原本 collection 的 `hashCode()` 跟 `equals()`,
而是使用 `Object` 的 method。
当原本的 collection 是 set 或 list 时,
就需要 preserve the contract of these operation(译注:翻译不能 Orz)。
这句话讲的相当暧昧不明,它背後的原因是什麽?
在 [Stack Overflow] 有一个很棒的解释:
一个 `UnmodifiableList` 是一个 `UnmodifiableCollection`,
但是反过来说就不成立了。
一个包了 List 的 `UnmodifiableCollection` 并不是一个 `UnmodifiableList`。
所以如果你要比较一个包了 foo 这个 `List` 的 `UnmodifiableCollection`、
跟包了同样 `List` foo 的 `UnmodifiableList`,
这两个并不会相等。
如果你直接取得被 wrap 的 list,它们就会相等。
虽然这个推论是正确的,但是它的影响可能完全在意料之外。
[Collections]:
http://docs.oracle.com/javase/7/docs/api/java/util/
Collections.html
[quirk in JavaDoc]:
http://docs.oracle.com/javase/7/docs/api/java/util/
Collections.html
#unmodifiableCollection(java.util.Collection)
[Stack Overflow]:
http://stackoverflow.com/questions/
12851229/hashcode-and-equals-for-collections-unmodifiablecollection/
12851469
#12851469
什麽叫底线...
-------------
底线就是你不可以倚赖 `Collections.equals()`。
虽然 `List.equals()` 跟 `Set.equals() 有良好定义,
但是不要信任 Collection.equals(),它的行为可能没有意义。
当你在 method signature 接了一个 collection 时请记得:
public class MyClass {
public void doStuff(Collection<?> collection) {
// Don't rely on collection.equals() here!
}
}
译注
----
如果看不懂这篇在干麽,那容许我画蛇添足一下。
`Collections.unmodifiableCollection()` 的内容是:
return new UnmodifiableCollection<T>(c);
而 `UnmodifiableCollection` 是实作 `Collection`,
其实是一个 delegate pattern:
static class UnmodifiableCollection<E> implements
Collection<E>, Serializable {
final Collection<? extends E> c;
UnmodifiableCollection(Collection<? extends E> c) {
if (c==null)
throw new NullPointerException();
this.c = c;
}
}
重点在於,`UnmodifiableCollection` 并没有实作 `hashCode()` 跟 `equals()`,
所以当你要一个 `UnmodifiableCollection` 作 `hashCode()` 时,
会直接使用 `Object` 的 `hashCode()`。
--
钱锺书:
说出来的话
http://www.psmonkey.org
比不上不说出来的话
Java 版 cookcomic 版
只影射着说不出来的话
and more......
--
※ 发信站: 批踢踢实业坊(ptt.cc)
◆ From: 114.25.13.90
※ 编辑: PsMonkey 来自: 114.25.13.90 (03/22 15:59)