简体   繁体   中英

When does a.equals(a) return false?

I was wondering which are the cases where a variable in java could not be equal (using the equals() method) to itself. I am not talking object here but the variable itself (as long as the code compiles and return false when calling equals). The only situation in which it does that I found so far is:

public class A {
    public static void main(String args[]){
        A a = new A();
        System.out.println(a.equals((a = null)));
    }
}

Is there any other case in which a.equals(a) would return false?

EDIT: no overriding of equals() is allowed but you can Modify (cast, inherit) a as much as you want as long as the variable a compare itself in the end.

It could return false in multithreaded contexts, even with an equals implementation that fulfills the equals contract :

class Test {
    public static final A a = new A();

    public static void main(String... args) throws Exception {
        new Thread() {
            @Override
            public void run() {
                while (true) {
                    a.x += 1;
                }
            }
        }.start();
        Thread.sleep(10);

        System.out.println(a.equals(a));  // <---
    }
}

class A {
    int x;

    @Override
    public boolean equals(Object o) {
        return (o instanceof A) && ((A)o).x == x;
    }
}
false

From the Object documentation of Oracle:

public boolean equals(Object obj)

Indicates whether some other object is "equal to" this one.

The equals method implements an equivalence relation on non-null object references:

It is symmetric: for any non-null reference values x and y, x.equals(y) should return true if and only if y.equals(x) returns true.
It is transitive: for any non-null reference values x, y, and z, if x.equals(y) returns true and y.equals(z) returns true, then x.equals(z) should return true.
It is consistent: for any non-null reference values x and y, multiple invocations of x.equals(y) consistently return true or consistently return false, provided no information used in equals comparisons on the objects is modified.
For any non-null reference value x, x.equals(null) should return false. 

The equals method for class Object implements the most discriminating possible equivalence relation on objects; that is, for any non-null reference values x and y, this method returns true if and only if x and y refer to the same object (x == y has the value true).

Note that it is generally necessary to override the hashCode method whenever this method is overridden, so as to maintain the general contract for the hashCode method, which states that equal objects must have equal hash codes.

Parameters: obj - the reference object with which to compare. Returns: true if this object is the same as the obj argument; false otherwise.

So coming back to your question and analizing the documentation

It's false when a.equals(null); and when a and b (Objects of the classes A and B respectively) are compared, ie a.equals(b) will return false too.

In other cases it's true, because of:

It is reflexive: for any non-null reference value x, x.equals(x) should return true.

It clearly says that: not null reference to x (or a in this case):

a.equals(a); will be true

I support khale's and Frakcool's reply. In addition to that if you just need another case to get false try

System.out.println(a.equals((a = new A())));

The assignment essentially returns what is being assigned and that will equate to false if its not the calling object itself.

I don't think there is a way we can get this done, since calling equals to itself is always true. Let me explain what you're trying to achieve.

String foo = "";
bool a = foo.equals(foo); // Here true, the easy one
foo = "some value";
bool b = foo.equals(foo); // Here true, since it's changed and then compared to itself again
bool c = foo.equals(foo="some other value"); // Here should be true again, since the compiler takes first the arguments, makes the assignation, and then makes the equals method execution, so in compiler what happens is:
// 1. Make foo = "some other value"
// 2. Compares foo with foo
// Foo is already changed, so is equals to itself

I haven't tried myself, but that's what should happen. If for some reason compiler breaks in line bool c = ... it's because equals does not receive String instantiation as a String parameter.

With a correctly implemented .equals() , a.equals(a) will never be false.

Passing an expression to the equals method:

a.equals(a = null);

is no more special than:

a.equals(b); or a.equals(null);

You're just comparing two different values, stuffing an expression into the equals calls doesn't change that.

A very interesting case is the one where you have a boxed Float , consider this code:

Float alpha = +0.0f;
Float beta = -0.0f;
boolean equal = alpha.equals(beta);
System.out.println("Equal: " + equal);

boolean equality = alpha.floatValue() == beta.floatValue();
System.out.println("Equality: " + equality);

This will print true for the first one and false for the second.

The opposite is true of the case of Float.NaN .

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