4

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.

arshajii
  • 127,459
  • 24
  • 238
  • 287
Paiku Han
  • 581
  • 2
  • 16
  • 38
  • How can something not be equal to itself? If that were possible the whole universe would be upside down and inside out. – PaulG May 23 '14 at 17:29
  • 3
    Are you considering the case where `equals()` is tampered with in order to return false in all cases? – nanofarad May 23 '14 at 17:30
  • 3
    `@Override public boolean equals(Object obj) { return false; }` – Marco Acierno May 23 '14 at 17:30
  • 3
    that won't compile... `a` variable isn't defined – Frakcool May 23 '14 at 17:32
  • 1
    @PaulG ;) As I said I am not talking about the Object that a is pointing to but the `a` variable itself. proof is in my example `a.equals(a = null)` returns false because after the call of equals() `a` is pointing to `null` – Paiku Han May 23 '14 at 17:33
  • @hexafraction and Marco I am not considering that case sorry – Paiku Han May 23 '14 at 17:34
  • Gotcha! That was my Friday afternoon wise comment. – PaulG May 23 '14 at 17:35
  • @Frakcool My example does compile and only after the call to equals() `a` is undefined – Paiku Han May 23 '14 at 17:35
  • why not read the doc at http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#equals(java.lang.Object). Ultimately .equals can be overridden, so to ask when it will return false for a given object, requires you to know the implementation of .equals if it was overridden. The default implementation in object compares object references, so only when the references arent equal, like say a deep copy of the original. – Mark W May 23 '14 at 17:38
  • @MarkW as I told hexafraction no overriding of equals allowed I read the javadoc that's how I found out about `a.equals(a)`. I'll edit the questions so that's it's clear – Paiku Han May 23 '14 at 17:41
  • i am surprised you can compile this. passing a = null as a parameter to equals is a horrendous thing to do. – Nathan Hughes May 23 '14 at 17:41
  • @MarkW you're absolutely right sorry again I used a 't' in my code but since the question was about 'a' I had to edit it and forgot about A t = new A() – Paiku Han May 23 '14 at 17:56
  • @PaikuHan +1 ya for the edit and a decent question. – Mark W May 23 '14 at 17:57

6 Answers6

4

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
arshajii
  • 127,459
  • 24
  • 238
  • 287
  • 1
    A non thread-safe equals() implementation being used in a threaded context is _not_ "perfectly valid". – Dmitri May 23 '14 at 18:01
  • @Dmitri I was trying to convey that an `equals` that appears to satisfy the `equals` contract can result in `a.equals(a)` returning false in a threaded context. Obviously it's invalid in the sense that it's poor design. I edited in an attempt to clarify. – arshajii May 23 '14 at 18:05
2

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, i.e. 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

Frakcool
  • 10,915
  • 9
  • 50
  • 89
1

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.

Syam S
  • 8,421
  • 1
  • 26
  • 36
0

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.

unmultimedio
  • 1,224
  • 2
  • 13
  • 39
0

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.

Dmitri
  • 8,999
  • 5
  • 36
  • 43
0

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.

skiwi
  • 66,971
  • 31
  • 131
  • 216