0

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.

Community
  • 1
  • 1
Jagger
  • 10,350
  • 9
  • 51
  • 93
  • 2
    Similar question [here](http://stackoverflow.com/questions/2165246/is-there-any-runtime-cost-for-casting-in-java) with an [answer](http://stackoverflow.com/a/2165276/5064389). – sweerpotato Oct 01 '15 at 11:32

1 Answers1

2

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
wero
  • 32,544
  • 3
  • 59
  • 84
  • That's interesting but keep in mind that Eclipse uses a JIT compiler and not the default javac. So that compiler might produce a different output. – David ten Hove Oct 01 '15 at 11:33
  • @DavidtenHove edited the answer, actually also javac of JDK 8 produces three checkcasts. Eclipse has no JIT compiler its just a replacement of javac – wero Oct 01 '15 at 11:36
  • Would you mind posting the decompiled code here? – Keppil Oct 01 '15 at 11:40