这个问题是由奇怪的HashMap.put()行为引起的
我想我明白为什么Map
需要K
而Map
采取的Object
,似乎不这样做会打破太多现有的代码.
现在我们陷入了一个容易出错的场景:
java.util.HashMapm = new java.util.HashMap (); m.put(5L,"Five"); // compiler barfs on m.put(5, "Five") m.contains(5); // no complains from compiler, but returns false
无法这一已被如果返回true解决Long
值withing int
范围和值相等?
这是Long.java的源代码
public boolean equals(Object obj) { if (obj instanceof Long) { return value == ((Long)obj).longValue(); } return false; }
即它必须是Long类型才能相等.我认为之间的关键区别是:
long l = 42L int i = 42; l == i
并且上面的示例是使用基元可以发生int值的隐式加宽,但是对于对象类型,没有用于从Integer隐式转换为Long的规则.
另外看看Java Puzzlers,它有很多类似的例子.
一般来说,尽管在equals()的约定中没有严格表达,但是对象不应该认为自己等于不是完全相同类的另一个对象(即使它是一个子类).考虑对称属性 - 如果a.equals(b)为真,那么b.equals(a)也必须为真.
让我们有两个对象,foo
类Super
和bar
类Sub
,它们可以扩展Super
.现在考虑equals()
在Super中的实现,特别是当它被称为foo.equals(bar)
.Foo只知道bar是强类型的Object
,因此要获得准确的比较,需要检查它是Super的实例,如果不是返回false.是的,所以这部分很好.它现在比较所有实例字段等(或实际的比较实现),并找到它们相等.到现在为止还挺好.
但是,根据合约,如果知道bar.equals(foo)也将返回true,则它只能返回true.由于bar可以是Super的任何子类,因此不清楚equals()方法是否会被覆盖(如果可能的话).因此,为了确保您的实现是正确的,您需要对称地编写它并确保两个对象是同一个类.
更基本的是,不同类的对象实际上不能被认为是相等的 - 因为在这种情况下,例如,只能将其中一个插入到a中HashSet
.
是的,但这一切都取决于比较算法以及转换的距离.例如,您尝试时想要发生什么m.Contains("5")
?或者如果你传递一个数组,其中5作为第一个元素?简单地说,它似乎是"如果类型不同,键是不同的".
然后拿一个带有object
关键字的集合.你有什么要发生,如果你put
一个5L
,然后试图让5
,"5"
,...?如果你put
一5L
和5
和"5"
,并要检查的5F
?
由于它是一个通用集合(或模板化,或任何你想称之为),它必须检查并对某些值类型进行一些特殊的比较.如果K int
然后检查是否传递的对象是long
,short
,float
,double
,...,然后转换和比较.如果K float
然后检查传递的对象是否...
你明白了.
如果类型不匹配,另一种实现可能是抛出异常,但我经常希望它能做到.