I tend to write my equals method in Java as a one liner...
class Test {
private String a = "";
private Integer b = Integer.MIN_VALUE;
private Long c = Long.MIN_VALUE;
public Test(final String a, final Integer b, final Long c) {
this.a = a;
this.b = b;
this.c = c;
}
@Override
public boolean equals(final Object obj) {
return obj instanceof Test && ((Test) obj).a.equals(this.a)
&& ((Test) obj).b.equals(this.b)
&& ((Test) obj).c.equals(this.c);
}
}
As you can see, in this approach I downcast the Object instance to Test instance many times. My question is, will it be optimised by the compiler so there will be a single downcast instead of three like if I wrote my equals method like this?
public boolean equals(final Object obj) {
if (obj instanceof Test) {
final Test test = (Test) obj;
return test.a.equals(this.a) && test.b.equals(this.b)
&& test.c.equals(this.c);
} else {
return false;
}
}
It is not a duplicate of the question in comment, because I am interested here in brevity of the implementation of the equals method (6 lines against 3) but not at cost of a performance degradation. In the other question the difference is one line.
When I decompile the class I find that the Eclipse compiler and javac
indeed produce three checkcast
instructions in the equals
method, so no optimization takes place.
When optimized by Hotspot it could be that hotspot can figure out that one cast is enough.
The decompiled byte code:
public boolean equals(java.lang.Object);
Code:
0: aload_1
1: instanceof #13 // class sov/Test
4: ifeq 62
7: aload_1
8: checkcast #13 // class sov/Test
11: getfield #3 // Field a:Ljava/lang/String;
14: aload_0
15: getfield #3 // Field a:Ljava/lang/String;
18: invokevirtual #14 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
21: ifeq 62
24: aload_1
25: checkcast #13 // class sov/Test
28: getfield #7 // Field b:Ljava/lang/Integer;
31: aload_0
32: getfield #7 // Field b:Ljava/lang/Integer;
35: invokevirtual #15 // Method java/lang/Integer.equals:(Ljava/lang/Object;)Z
38: ifeq 62
41: aload_1
42: checkcast #13 // class sov/Test
45: getfield #12 // Field c:Ljava/lang/Long;
48: aload_0
49: getfield #12 // Field c:Ljava/lang/Long;
52: invokevirtual #16 // Method java/lang/Long.equals:(Ljava/lang/Object;)Z
55: ifeq 62
58: iconst_1
59: goto 63
62: iconst_0
63: ireturn