简体   繁体   中英

Why does object.equals(new Integer(1)) equate to true?

I am struggling to understand this 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
}

As far as I understand, because object is an instance of the Object class, the .equals() method has not been overwritten, and therefore checks for object equality.

If new Integer(1) creates a new instance, then it should be a separate object to object . Following my train of thought, the correct answer should be false , but only true makes this pass. Where is the flaw in my logic?

Edit: I understand that integers between -128 and 127 are cached. If my understanding of the object object is correct (as stated above), then this is irrelevant.

Integer overrides equals and checks if the underlying int is equal to the int of the other Integer instance, and if so, returns true . The reason why Integer's equals method is invoked, and not the one from Object, is that the runtime type of object is Integer.

Integer is an Object, but due to the overridden equals , no object identity is used.

All following boolean expressions evaluate to 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));

Now consider autoboxing, which reuses instances for values in the range [-128,127]. The following statements about object equality are all evaluating to 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

You are calling equals on an Integer object instance. It is dispatched at run-time to the implementation in the Integer class (which regards the Integer equal to any other Integer of the same numeric value). The compile-time type (the static type of the variable involved) does not (directly) matter.

If that was not the case, how would something like this work (where the interfaces involved have no implementations at all):

 Comparable<Integer> a = 1;
 Serializable b = 1;
 assertTrue(a.equals(b));

Note that static methods are "dispatched" at compile-time. That's why you should call them using the class name, not an object instance (which is ignored, can even be null, and the compiler issues a warning).

As far as I understand, because object is an instance of the Object class, the .equals() method has not been overwritten, and therefore checks for object equality.

You've got this one completely wrong. Even though the static type of variable object is Object , it remains an instance of Integer . That is why equals() is directed to Integer 's override, producing the right result.

Assigning an instance to a variable of base type, or an interface implemented by the class, does not "strip" the object of its subclass behavior. In particular, an instance of Integer retains all its behaviors as implemented in the Integer class, even though you have assigned the instance to a variable of type Object .

Heard of Dynamic Method Dispatch ?

When you use a super class reference to refer to subclass object, and if subclass has overridden method, this overridden method will be called.

Hence, though you are using Object object = new Integer(1); , calling equals on object will always call Integer.equals() .

And Integer.equals() checks for integers' equality, not necessarily same same reference.

If new Integer(1) creates a new instance, then it should be a separate object to object.

That's where you are going wrong. A new instance of Integer(1) will be false for == but true for equals .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM