为什么object.equals(new Integer(1))等于true?

时间:2016-04-21 09:14:27

标签: java

我正在努力理解这个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
}

据我所知,因为objectObject类的一个实例,所以.equals()方法没有被覆盖,因此会检查对象是否相等。

如果new Integer(1)创建了一个新实例,那么它应该是object的单独对象。按照我的思路,正确的答案应该是false,但只有true才能通过。我逻辑中的缺陷在哪里?

编辑:我知道-128和127之间的整数是缓存的。如果我对object对象的理解是正确的(如上所述),那么这是无关紧要的。

5 个答案:

答案 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)

  

据我所知,因为objectObject类的一个实例,所以.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的新实例==trueequals22-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