Decompilar clases Java

JD-Core es un decompilador de clases Java que destaca, entre otras cosas, porque, a diferencia del popular Jad, soporta algunas de las novedades más importantes introducidas en Java 5, como los generics o el tipo enum. Este decompilador cuenta con dos interfaces, una aplicación standalone llamada JD-GUI y un plugin para Eclipse llamado JD-Eclipse.

Vamos a crear una pequeña clase de ejemplo para demostrar su funcionamiento.

import java.util.EnumSet;

public class Ejemplo {
  enum Dia {
    LUNES, MARTES, MIERCOLES, JUEVES, VIERNES, SABADO, DOMINGO
  }

  public static void main(String[] args) {
    for (Dia dia : EnumSet.allOf(Dia.class))
      System.out.println(dia);
  }
}

Si abrimos la vista de navegador en Eclipse (Window -> Show View -> Navigator) y hacemos doble clic sobre el archivo que representa a nuestra clase compilada en la carpeta bin, se lanzará el visor de clases, mostrando el bytcode de la clase. También podemos utilizar la herramienta javap, incluída en el JDK:

javap -c Ejemplo

El bytecode de nuestra clase tiene el siguiente aspecto:

// Compiled from Ejemplo.java (version 1.6 : 50.0, super bit)
public class Ejemplo {
  
  // Method descriptor #6 ()V
  // Stack: 1, Locals: 1
  public Ejemplo();
    0  aload_0 [this]
    1  invokespecial java.lang.Object() [8]
    4  return
      Line numbers:
        [pc: 0, line: 3]
      Local variable table:
        [pc: 0, pc: 5] local: this index: 0 type: Ejemplo
  
  // Method descriptor #15 ([Ljava/lang/String;)V
  // Stack: 2, Locals: 3
  public static void main(java.lang.String[] args);
     0  ldc <Class Ejemplo$Dia> [16]
     2  invokestatic java.util.EnumSet.allOf(java.lang.Class) : java.util.EnumSet [18]
     5  invokevirtual java.util.EnumSet.iterator() : java.util.Iterator [24]
     8  astore_2
     9  goto 29
    12  aload_2
    13  invokeinterface java.util.Iterator.next() : java.lang.Object [28] [nargs: 1]
    18  checkcast Ejemplo$Dia [16]
    21  astore_1 [dia]
    22  getstatic java.lang.System.out : java.io.PrintStream [34]
    25  aload_1 [dia]
    26  invokevirtual java.io.PrintStream.println(java.lang.Object) : void [40]
    29  aload_2
    30  invokeinterface java.util.Iterator.hasNext() : boolean [46] [nargs: 1]
    35  ifne 12
    38  return
      Line numbers:
        [pc: 0, line: 9]
        [pc: 22, line: 10]
        [pc: 29, line: 9]
        [pc: 38, line: 11]
      Local variable table:
        [pc: 0, pc: 39] local: args index: 0 type: java.lang.String[]
        [pc: 22, pc: 29] local: dia index: 1 type: Ejemplo.Dia
      Stack map table: number of frames 2
        [pc: 12, full, stack: {}, locals: {java.lang.String[], _, java.util.Iterator}]
        [pc: 29, same]

  Inner classes:
    [inner class info: #16 Ejemplo$Dia, outer class info: #1 Ejemplo
     inner name: #59 Dia, accessflags: 16408 static final]
}

Como vemos en realidad el bucle for each se convierte en un bucle que utiliza un iterador.

Si usamos el decompilador jad el resultado será:

import java.io.PrintStream;
import java.util.EnumSet;
import java.util.Iterator;

public class Ejemplo {
  static final class Dia extends Enum {
    public static Dia[] values() {
      Dia adia[];
      int i;
      Dia adia1[];
      System.arraycopy(adia = ENUM$VALUES, 0,
          adia1 = new Dia[i = adia.length], 0, i);
      return adia1;
    }

    public static Dia valueOf(String s) {
      return (Dia) Enum.valueOf(Ejemplo$Dia, s);
    }

    public static final Dia LUNES;
    public static final Dia MARTES;
    public static final Dia MIERCOLES;
    public static final Dia JUEVES;
    public static final Dia VIERNES;
    public static final Dia SABADO;
    public static final Dia DOMINGO;
    private static final Dia ENUM$VALUES[];

    static {
      LUNES = new Dia("LUNES", 0);
      MARTES = new Dia("MARTES", 1);
      MIERCOLES = new Dia("MIERCOLES", 2);
      JUEVES = new Dia("JUEVES", 3);
      VIERNES = new Dia("VIERNES", 4);
      SABADO = new Dia("SABADO", 5);
      DOMINGO = new Dia("DOMINGO", 6);
      ENUM$VALUES = (new Dia[] { LUNES, MARTES, MIERCOLES, JUEVES,
          VIERNES, SABADO, DOMINGO });
    }

    private Dia(String s, int i) {
      super(s, i);
    }
  }

  public Ejemplo() {
  }

  public static void main(String args[]) {
    Dia dia;
    for (Iterator iterator = EnumSet.allOf(Ejemplo$Dia).iterator(); iterator
        .hasNext(); System.out.println(dia))
      dia = (Dia) iterator.next();
  }
}

que como vemos no está demasiado mal, pero dista bastante del original.

Por último este es el resultado de JD-GUI:

import java.io.PrintStream;
import java.util.EnumSet;
import java.util.Iterator;

public class Ejemplo {
  public static void main(String[] args) {
    for (Iterator localIterator = EnumSet.allOf(Ejemplo.Dia.class)
        .iterator(); localIterator.hasNext();) {
      Ejemplo.Dia dia = (Ejemplo.Dia) localIterator.next();
      System.out.println(dia);
    }
  }

  static enum Dia {
    LUNES, MARTES, MIERCOLES, JUEVES, VIERNES, SABADO, DOMINGO;
  }
}


7 comentarios en «Decompilar clases Java»

  1. Pingback: JD-GUI, decompilar una clase Java « Ubuntu Life

  2. Pingback: 100 programas gratis « Bichotoblog

  3. Gracias, es una herramienta necesaria para decopilar clases realizadas en otros entornos y usarlos para eclipse, por citar un ejemplo.
    Abrazox

Responder a tsy Cancelar respuesta

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.