Java 编译和反编译

什么是编译

编译:
  • 将高级语言翻译成汇编语言或机器语言的过程 Java语言中的编译一般指将Java文件转换成class文件

顾名思义反编译就是编译的逆向过程

反编译:
  • 将汇编语言或机器语言反编译成高级语言的过程 Java语言中的反编译一般指将class文件转换成java文件

怎么实现编译和反编译

编译

Java的编译分为两步:
1)前端编译: * . java文件转换为 * .class文件(字节码文件)。Java的前端编译器主要是javac, Eclipse JDT 中的增量式编译器 ECJ 等。
2)后端编译:在经过后端编译器,将class字节码文件,编译成机器语言。Java的后端编译器主要是各大虚拟机实现的,如HotSpot中的JIT编译器。

反编译
  • 反编译作用

学习Java的一种方法。Java中源代码为.java文件,然后经过编译后生成计算机可识别的.class文件,但是.class文件是计算机识别的,因此需要反编译变成程序员能看懂的代码,但是反编译后的代码并不是和源码一模一样,而是非常接近的。并且经过反编译,也可以学习别人的代码。

  • 反编译方法

Java文件编译后编程字节码文件(class文件),我们无法看懂,要是想要看懂就需要反编译。反编译的一种简单方法:(使用IDEA)把class文件,拖拽到IntelliJ IDEA工具中,IntelliJ自动进行反编译

javap

javap是jdk自带的一个工具,可以对代码反编译,也可以查看java编译器生成的字节码。javap和其他两个反编译工具最大的区别是他生成的文件并不是java文件,也不像其他两个工具生成代码那样更容易理解。拿一段简单的代码举例,

public class switchDemoString {
    public static void main(String[] args) {
        String str = "world";
        switch (str) {
            case "hello":
                System.out.println("hello");
                break;
            case "world":
                System.out.println("world");
                break;
            default:
                break;
        }
    }
}

通过javap反编译过后是这样的

public class com.hollis.suguar.switchDemoString {
  public com.hollis.suguar.switchDemoString();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: ldc           #2                  // String world
       2: astore_1
       3: aload_1
       4: astore_2
       5: iconst_m1
       6: istore_3
       7: aload_2
       8: invokevirtual #3                  // Method java/lang/String.hashCode:()I
      11: lookupswitch  { // 2
              99162322: 36
             113318802: 50
               default: 61
          }
      36: aload_2
      37: ldc           #4                  // String hello
      39: invokevirtual #5                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z
      42: ifeq          61
      45: iconst_0
      46: istore_3
      47: goto          61
      50: aload_2
      51: ldc           #2                  // String world
      53: invokevirtual #5                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z
      56: ifeq          61
      59: iconst_1
      60: istore_3
      61: iload_3
      62: lookupswitch  { // 2
                     0: 88
                     1: 99
               default: 110
          }
      88: getstatic     #6                  // Field java/lang/System.out:Ljava/io/PrintStream;
      91: ldc           #4                  // String hello
      93: invokevirtual #7                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      96: goto          110
      99: getstatic     #6                  // Field java/lang/System.out:Ljava/io/PrintStream;
     102: ldc           #2                  // String world
     104: invokevirtual #7                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
     107: goto          110
     110: return
}

jad

jad是一个比较不错的反编译工具,只要下载一个执行工具,就可以实现对class文件的反编译了。还是上面的源代码,使用jad反编译后内容如下:

命令:jad switchDemoString.class

public class switchDemoString
{
    public switchDemoString()
    {
    }
    public static void main(String args[])
    {
        String str = "world";
        String s;
        switch((s = str).hashCode())
        {
        default:
            break;
        case 99162322:
            if(s.equals("hello"))
                System.out.println("hello");
            break;
        case 113318802:
            if(s.equals("world"))
                System.out.println("world");
            break;
        }
    }
}

看,这个代码你肯定看的懂,因为这不就是标准的java的源代码么。这个就很清楚的可以看到原来字符串的switch是通过equals()和hashCode()方法来实现的。

CFR

jad很好用,但是无奈的是很久没更新了,所以只能用一款新的工具替代他,CFR是一个不错的选择,相比jad来说,他的语法可能会稍微复杂一些,但是好在他可以work。

如,我们使用cfr对刚刚的代码进行反编译。执行一下命令:

java -jar cfr_0_125.jar switchDemoString.class --decodestringswitch false

得到以下代码

public class switchDemoString {
    public static void main(String[] arrstring) {
        String string;
        String string2 = string = "world";
        int n = -1;
        switch (string2.hashCode()) {
            case 99162322: {
                if (!string2.equals("hello")) break;
                n = 0;
                break;
            }
            case 113318802: {
                if (!string2.equals("world")) break;
                n = 1;
            }
        }
        switch (n) {
            case 0: {
                System.out.println("hello");
                break;
            }
            case 1: {
                System.out.println("world");
                break;
            }
        }
    }
}

通过这段代码也能得到字符串的switch是通过equals()和hashCode()方法来实现的结论。

总结

其实我们常用的开发工具(例如:IDEA、Eclipse)都带有反编译功能,写此文章以做记录

你可能感兴趣的:(笔记,java,jvm,开发语言)