Search code examples
javadecompilingdecompiler

Why different Java de-compilers show different source code?


I am trying to understand how Java compiler works by de-compiling the .class files. I have used the Java decompiler (http://jd.benow.ca/) and showmycode (http://www.showmycode.com/) They show me different sourcecode in .java file. Why? Which should I trust.

.java file

class HelloWorld{
    public static void main(String[] args){
        System.out.println("Hello, World!");
    }
}

.class file as de-compiled by java decompiler:

import java.io.PrintStream;

class HelloWorld
{
  public static void main(String[] paramArrayOfString)
  {
    System.out.println("Hello, World!");
  }
}

.class file as de-compiled by showmycode

import java.io.PrintStream;
class HelloWorld {
   HelloWorld() {
   } 
   public static void main(string args[]) 
   {
       system.out.println("Hello, World!"); 
   }
}

Solution

  • A decompiler cannot recreate the original source code, it can only create a new source code which would compile into the same binary as the original source code.

    (Assuming that showmycode will fix their case issues, see below) The three source codes - the original one, the one created by java decompiler and the one created by showmycode are idempotent. They are written in different ways but do exactly the same thing. Both decompilers are right.

    Here's the differences explained:

    • Constructor present / absent: Every class has a constructor. If the programmer does not supply a constructor, the compiler will generate one. A smart decompiler will recognize this and assume for a constructor which is empty that it was generated and thus omit it from the decompiled source code.
    • Position of [] for arrays: The declarations String[] foo and String foo[] are the same. I recommend to always go for String[] foo, because in Java (as opposed to C), being an array is an attribute of the type, not the variable.
    • Formatting / placement of {}, indentation etc.: doesn't matter at all, mostly. It might matter a little bit for the debug information (line numbers of stack traces), but that's not part of the significant behavior of the code, which is what we'd be interested in.
    • Names of automatic variables (local variables incl. parameter variables) are not available in the binary, so the decompiler has to invent new names when decompiling.

    Note that showmycode seems to have an issue with case of type names. Java is case sensitive, and it must be System and String, not system and string. Seems like showmycode gets this wrong, which means that code cannot be compiled again unless you manually fix all these type names.

    Another issue of showmycode is how it deals with varargs methods. I changed the signature of main to public static void main(String... args) to see what I get, and I got public static transient void main(string args[]), which doesn't compile. Nowadays a decompiler is expected to produce correct, compilable source code, and showmycode doesn't.