我正在努力理解这个Koan:
@Koan
public void equalsMethodCanBeChangedBySubclassesToTestsIfTwoObjectsAreEqual() {
Object object = new Integer(1);
assertEquals(object.equals(object), true);
assertEquals(object.equals(new Integer(1)), __);
// Note: This means that for the class 'Object' there is no difference between 'equal' and 'same'
// but for the class 'Integer' there is difference - see below
}
据我所知,因为object
是Object
类的一个实例,所以.equals()
方法没有被覆盖,因此会检查对象是否相等。
如果new Integer(1)
创建了一个新实例,那么它应该是object
的单独对象。按照我的思路,正确的答案应该是false
,但只有true
才能通过。我逻辑中的缺陷在哪里?
编辑:我知道-128和127之间的整数是缓存的。如果我对object
对象的理解是正确的(如上所述),那么这是无关紧要的。
答案 0 :(得分:9)
整数覆盖equals
并检查基础int
是否等于另一个int
实例的Integer
,如果是,则返回true
。调用Integer的equals
方法而不是Object的方法的原因是object
的运行时类型是Integer。
Integer是一个Object,但是由于被覆盖的equals
,没有使用对象标识。
以下所有布尔表达式的计算结果为true:
print((new Integer(1).equals(1)));
print((new Integer(1).equals(new Integer(1))));
print((((Integer) 1).equals(new Integer(1))));
print(((Integer) 1).equals(1));
现在考虑自动装箱,它会重复使用范围[-128,127]范围内的值的实例。以下关于对象相等性的陈述都在评估true
:
1 == ((Integer) 1)
((Integer) (-128)) == ((Integer) (-128)) // in autoboxing range
((Integer) (+127)) == ((Integer) (+127)) // same
((Integer) (-200)) != ((Integer) (-200)) // not autoboxing
((Integer) (+200)) != ((Integer) (+200)) // same
((Integer) (-128)) != (new Integer(-128)) // explicit new instance, so no autoboxing
((Integer) (+127)) != (new Integer(+127)) // same
答案 1 :(得分:4)
您正在Integer对象实例上调用equals
。它是在运行时分派给Integer类中的实现(它将Integer视为等于同一数值的任何其他Integer)。编译时类型(涉及的变量的静态类型)不(直接)重要。
如果不是这样的话,那么这样的工作会怎样(所涉及的接口根本没有实现):
Comparable<Integer> a = 1;
Serializable b = 1;
assertTrue(a.equals(b));
请注意静态方法是&#34;调度&#34;在编译时。这就是为什么你应该使用类名调用它们,而不是对象实例(被忽略,甚至可以为null,编译器发出警告)。
答案 2 :(得分:4)
据我所知,因为
object
是Object
类的一个实例,所以.equals()
方法没有被覆盖,因此会检查对象是否相等。
你完全错了。即使变量object
的静态类型为Object
,它仍然是Integer
的实例。这就是为什么equals()
被定向到Integer
的覆盖,产生正确的结果。
将实例分配给基类型变量或由类实现的接口不会“剥离”其子类行为的对象。特别是,Integer
的实例保留了Integer
类中实现的所有行为,即使您已将实例分配给Object
类型的变量。
答案 3 :(得分:2)
听说Dynamic Method Dispatch
?
当您使用超类引用引用子类对象时,如果子类具有重写方法,则将调用此重写方法。
因此,尽管您使用Object object = new Integer(1);
,但在对象上调用equals将始终调用Integer.equals()
。
并且Integer.equals()
检查整数的相等性,不一定是相同的引用。
答案 4 :(得分:1)
如果新的Integer(1)创建了一个新实例,那么它应该是一个单独的对象对象。
那是你出错的地方。 false
的新实例==
为true
,equals
为22-03-2016 0 0 15 15
23-03-2016 1 2 12 15
24-03-2016 0 1 15 16
25-03-2016 0 1 9 10
26-03-2016 0 0 1 1
28-03-2016 0 0 13 13
29-03-2016 0 0 17 17
30-03-2016 0 1 19 20
31-03-2016 0 1 10 11
。