adn*_*nan 5 java collections effective-java
Bloch的精彩书籍"Effective Java"指出,如果equals不对称,则Collections的行为contains是不确定的.
在他给出的例子中(通过下面的小修改再现),布洛赫说他看到了"假",但也可以看到真实或异常.
如果标准没有指定contains(Object o)检查e.equals(o)或o.equals(e)集合中的每个项目以及前者是否已实现,则可以看到"true" .然而,Collections Javadoc明确指出它必须是后者(这是我观察到的).
所以我看到的唯一可能是"假"或可能是异常(但是字符串Javadoc似乎排除了后者).
我理解更广泛的观点,非对称性可能equals会导致集合之外的代码出现问题,但我不会在他引用的例子中看到它.
我错过了什么吗?
import java.util.List;
import java.util.ArrayList;
class CIString {
private final String s;
public CIString(String s) {
this.s = s;
}
@Override public boolean equals( Object o ) {
System.out.println("Calling CIString.equals from " + this.s );
if ( o instanceof CIString)
return s.equalsIgnoreCase( ( (CIString) o).s);
if ( o instanceof String)
return s.equalsIgnoreCase( (String) o );
return false;
}
// Always override hashCode when you override equals
// This is an awful hash function (everything collides -> performance is terrible!)
// but it is semantically sound. See Item 10 from Effective Java for more details.
@Override public int hashCode() { return 42; }
}
public class CIS {
public static void main(String[] args) {
CIString a = new CIString("Polish");
String s = "polish";
List<CIString> list = new ArrayList<CIString>();
list.add(a);
System.out.println("list contains s:" + list.contains(s));
}
}
Run Code Online (Sandbox Code Playgroud)
现在是凌晨,所以也许我错过了你问题的真正要点,这段代码将失败:
\n\npublic class CIS \n{\n public static void main(String[] args) \n {\n CIString a = new CIString("Polish");\n String s = "polish";\n\n List<String> list = new ArrayList<String>();\n list.add(s);\n System.out.println("list contains a:" + list.contains(a));\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n\n至少,你的代码找到它而我的代码没有找到它是很奇怪的(从理智的角度来看,这并不是你的代码显然是如何编写的:-)
\n\n编辑:
\n\npublic class CIS {\n public static void main(String[] args) {\n CIString a = new CIString("Polish");\n String s = "polish";\n\n List<CIString> list = new ArrayList<CIString>();\n list.add(a);\n System.out.println("list contains s:" + list.contains(s));\n\n List<String> list2 = new ArrayList<String>();\n list2.add(s);\n System.out.println("list contains a:" + list2.contains(a));\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n\n现在代码打印出来:
\n\nlist contains s:false\nCalling CIString.equals from Polish\nlist contains a:true\nRun Code Online (Sandbox Code Playgroud)\n\n这仍然没有意义……而且非常脆弱。如果两个对象像 a.equals(b) 一样相等,那么它们也必须像 b.equal(a) 一样相等,但您的代码并非如此。
\n\n来自javadoc:
\n\n\n\n\n它是对称的:对于任何非空引用值 x 和 y,当且仅当 y.equals(x) 返回 true 时,\n x.equals(y) 才应返回 true。
\n
所以,是的,书中的示例可能与集合 API 的 Javadoc 相矛盾,但原理是正确的。人们不应该创建一个行为奇怪的 equals 方法,否则最终会出现问题。
\n\n编辑2:
\n\n正文的要点是:
\n\n\n\n\n在 Sun\xe2\x80\x99s 当前的实现中,它恰好返回 false,但是 \n\xe2\x80\x99s 只是一个实现工件。在另一个实现中,它可以轻松地返回 true 或抛出运行时异常。一旦你违反了 equals 契约,你就根本不知道其他对象在面对你的对象时会如何表现。
\n
然而,考虑到 Javadoc 所说的内容,该行为似乎是固定的,而不是实现工件。
\n\n如果它不在 javadoc 中,或者 javadoc 不属于规范的一部分,那么它可能会在以后发生更改,并且代码将不再工作。
\n| 归档时间: |
|
| 查看次数: |
923 次 |
| 最近记录: |