idea java反编译工具_javap命令与Java Dcompiler工具、IDEA自带的反编译器反编译的结果的差别及原因...

问题描述

写这篇文章是为了记录我这几天遇到的一个疑惑,并且顺藤摸瓜的学习一下javap命令。遇到的疑惑是这样的:我在看“使用枚举类型实现单列模式”的博客时,发现一些博客中写到的枚举类型的反编译结果包含的信息不尽相同:

一些对枚举类的反编译结果仅仅包含像我们正常编写的枚举类的一些信息,如使用IDEA,Java Decompiler;

而另一些反编译结果则完全不同:一方面枚举类成为了普通的class类,只是它继承了Enum类,枚举值都是public static final形式的对象;另一方面还多了static块,values(),valueof()这些方法。

源代码:

public enum Season {

SPIRNG,

SUMMER,

AUTUMN,

WINTER;

public String allSeasons() {

return SPIRNG.name() + " " + SUMMER.name() + " " + AUTUMN.name() +" " +WINTER.name();

}

}

使用javap -c Season.class命令反编译结果:

public final class Season extends java.lang.Enum {

public static final Season SPIRNG;

public static final Season SUMMER;

public static final Season AUTUMN;

public static final Season WINTER;

public static Season[] values();

Code:

0: getstatic #1 // Field $VALUES:[LSeason;

3: invokevirtual #2 // Method "[LSeason;".clone:()Ljava/lang/Object;

6: checkcast #3 // class "[LSeason;"

9: areturn

public static Season valueOf(java.lang.String);

Code:

0: ldc #4 // class Season

2: aload_0

3: invokestatic #5 // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;

6: checkcast #4 // class Season

9: areturn

public java.lang.String allSeasons();

Code:

0: new #7 // class java/lang/StringBuilder

3: dup

4: invokespecial #8 // Method java/lang/StringBuilder."":()V

7: getstatic #9 // Field SPIRNG:LSeason;

10: invokevirtual #10 // Method name:()Ljava/lang/String;

13: invokevirtual #11 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;

16: ldc #12 // String

18: invokevirtual #11 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;

21: getstatic #13 // Field SUMMER:LSeason;

24: invokevirtual #10 // Method name:()Ljava/lang/String;

27: invokevirtual #11 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;

30: ldc #12 // String

32: invokevirtual #11 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;

35: getstatic #14 // Field AUTUMN:LSeason;

38: invokevirtual #10 // Method name:()Ljava/lang/String;

41: invokevirtual #11 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;

44: ldc #12 // String

46: invokevirtual #11 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;

49: getstatic #15 // Field WINTER:LSeason;

52: invokevirtual #10 // Method name:()Ljava/lang/String;

55: invokevirtual #11 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;

58: invokevirtual #16 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;

61: areturn

static {};

Code:

0: new #4 // class Season

3: dup

4: ldc #17 // String SPIRNG

6: iconst_0

7: invokespecial #18 // Method "":(Ljava/lang/String;I)V

10: putstatic #9 // Field SPIRNG:LSeason;

13: new #4 // class Season

16: dup

17: ldc #19 // String SUMMER

19: iconst_1

20: invokespecial #18 // Method "":(Ljava/lang/String;I)V

23: putstatic #13 // Field SUMMER:LSeason;

26: new #4 // class Season

29: dup

30: ldc #20 // String AUTUMN

32: iconst_2

33: invokespecial #18 // Method "":(Ljava/lang/String;I)V

36: putstatic #14 // Field AUTUMN:LSeason;

39: new #4 // class Season

42: dup

43: ldc #21 // String WINTER

45: iconst_3

46: invokespecial #18 // Method "":(Ljava/lang/String;I)V

49: putstatic #15 // Field WINTER:LSeason;

52: iconst_4

53: anewarray #4 // class Season

56: dup

57: iconst_0

58: getstatic #9 // Field SPIRNG:LSeason;

61: aastore

62: dup

63: iconst_1

64: getstatic #13 // Field SUMMER:LSeason;

67: aastore

68: dup

69: iconst_2

70: getstatic #14 // Field AUTUMN:LSeason;

73: aastore

74: dup

75: iconst_3

76: getstatic #15 // Field WINTER:LSeason;

79: aastore

80: putstatic #1 // Field $VALUES:[LSeason;

83: return

}

使用Java Decompiler工具的反编译结果:

public enum Season

{

SPIRNG, SUMMER, AUTUMN, WINTER;

private Season() {}

public String allSeasons()

{

return SPIRNG.name() + " " + SUMMER.name() + " " + AUTUMN.name() + " " + WINTER.name();

}

}

从上面反编译的结果我们总结差别如下

javap反编译的结果中类的声明不同,它是一个继承了Enum类并且声明为final类型的类;

javap反编译结果中包含的方法不同,它包含了static(),valueOf(),values()方法;

javap反编译结果中的方法体不同,它的方法体使用jvm指令来描述。

javap命令

C:\Users\w00457192>javap -h

用法: javap

其中, 可能的选项包括:

-? -h --help -help 输出此帮助消息

-version 版本信息

-v -verbose 输出附加信息

-l 输出行号和本地变量表

-public 仅显示公共类和成员

-protected 显示受保护的/公共类和成员

-package 显示程序包/受保护的/公共类和成员 (默认)

-p -private 显示所有类和成员

-c 对代码进行反汇编

-s 输出内部类型签名

-sysinfo 显示正在处理的类的系统信息 (路径, 大小, 日期, MD5 散列)

-constants 显示最终常量

--module , -m 指定包含要反汇编的类的模块

--module-path 指定查找应用程序模块的位置

--system 指定查找系统模块的位置

--class-path 指定查找用户类文件的位置

-classpath 指定查找用户类文件的位置

-cp 指定查找用户类文件的位置

-bootclasspath 覆盖引导类文件的位置

从上面的信息我们可以看出javap -c是用于反汇编,而不是反编译。参考维基百科的解释如下:

反汇编器(disassembler)是一种将机器语言转换为汇编语言的计算机程序——这与汇编器的目的相反。反汇编器与反编译器不同,反编译器的目标是高级语言而非汇编语言。反汇编器的反汇编输出通常格式化为适合人类阅读,而非用作汇编器的输入源,因此它主要是一个逆向工程工具。

结论

现在我们可以理解为什么javap和Java Decompiler的输出中方法体有所不同了。

至于为什么Java Decompiler没有包含static块和values(),valueof()方法,我推测是因为反编译器的目的是反编译出源码,而我们可以确定的是static块和values()和valueof()这两个方法是编译器自己实现的,不是我们人为添加的,所以在反编译器看来这不属于源码的一部分,因此没有在编译的结果中包含这些方法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值