Intellij Idea 为什么show bytecode和class file不匹配?

x33g5p2x  于 2024-01-06  发布在  其他
关注(0)|答案(2)|浏览(181)

原始.java文件

  1. public enum Fruit {
  2. ORANGE(1), APPLE(2);
  3. private final int i;
  4. Fruit(int i){
  5. this.i=i;
  6. }
  7. }

字符串

.class文件

  1. //
  2. // Source code recreated from a .class file by IntelliJ IDEA
  3. // (powered by FernFlower decompiler)
  4. //
  5. public enum Fruit {
  6. ORANGE,
  7. APPLE;
  8. private Fruit() {
  9. }
  10. }

显示字节码结果

  1. // class version 61.0 (61)
  2. // access flags 0x4031
  3. // signature Ljava/lang/Enum<LFruit;>;
  4. // declaration: Fruit extends java.lang.Enum<Fruit>
  5. public final enum Fruit extends java/lang/Enum {
  6. // compiled from: Fruit.java
  7. // access flags 0x4019
  8. public final static enum LFruit; ORANGE
  9. // access flags 0x4019
  10. public final static enum LFruit; APPLE
  11. // access flags 0x12
  12. private final I i
  13. // access flags 0x101A
  14. private final static synthetic [LFruit; $VALUES
  15. // access flags 0x9
  16. public static values()[LFruit;
  17. L0
  18. LINENUMBER 1 L0
  19. GETSTATIC Fruit.$VALUES : [LFruit;
  20. INVOKEVIRTUAL [LFruit;.clone ()Ljava/lang/Object;
  21. CHECKCAST [LFruit;
  22. ARETURN
  23. MAXSTACK = 1
  24. MAXLOCALS = 0
  25. // access flags 0x9
  26. public static valueOf(Ljava/lang/String;)LFruit;
  27. L0
  28. LINENUMBER 1 L0
  29. LDC LFruit;.class
  30. ALOAD 0
  31. INVOKESTATIC java/lang/Enum.valueOf (Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
  32. CHECKCAST Fruit
  33. ARETURN
  34. L1
  35. LOCALVARIABLE name Ljava/lang/String; L0 L1 0
  36. MAXSTACK = 2
  37. MAXLOCALS = 1
  38. // access flags 0x2
  39. // signature (I)V
  40. // declaration: void <init>(int)
  41. private <init>(Ljava/lang/String;II)V
  42. L0
  43. LINENUMBER 4 L0
  44. ALOAD 0
  45. ALOAD 1
  46. ILOAD 2
  47. INVOKESPECIAL java/lang/Enum.<init> (Ljava/lang/String;I)V
  48. L1
  49. LINENUMBER 5 L1
  50. ALOAD 0
  51. ILOAD 3
  52. PUTFIELD Fruit.i : I
  53. L2
  54. LINENUMBER 6 L2
  55. RETURN
  56. L3
  57. LOCALVARIABLE this LFruit; L0 L3 0
  58. LOCALVARIABLE i I L0 L3 3
  59. MAXSTACK = 3
  60. MAXLOCALS = 4
  61. // access flags 0x100A
  62. private static synthetic $values()[LFruit;
  63. L0
  64. LINENUMBER 1 L0
  65. ICONST_2
  66. ANEWARRAY Fruit
  67. DUP
  68. ICONST_0
  69. GETSTATIC Fruit.ORANGE : LFruit;
  70. AASTORE
  71. DUP
  72. ICONST_1
  73. GETSTATIC Fruit.APPLE : LFruit;
  74. AASTORE
  75. ARETURN
  76. MAXSTACK = 4
  77. MAXLOCALS = 0
  78. // access flags 0x8
  79. static <clinit>()V
  80. L0
  81. LINENUMBER 2 L0
  82. NEW Fruit
  83. DUP
  84. LDC "ORANGE"
  85. ICONST_0
  86. ICONST_1
  87. INVOKESPECIAL Fruit.<init> (Ljava/lang/String;II)V
  88. PUTSTATIC Fruit.ORANGE : LFruit;
  89. NEW Fruit
  90. DUP
  91. LDC "APPLE"
  92. ICONST_1
  93. ICONST_2
  94. INVOKESPECIAL Fruit.<init> (Ljava/lang/String;II)V
  95. PUTSTATIC Fruit.APPLE : LFruit;
  96. L1
  97. LINENUMBER 1 L1
  98. INVOKESTATIC Fruit.$values ()[LFruit;
  99. PUTSTATIC Fruit.$VALUES : [LFruit;
  100. RETURN
  101. MAXSTACK = 5
  102. MAXLOCALS = 0
  103. }


为什么show bytecode和class file不匹配?
我研究了如何在intellij中进行反编译过程,但我找不到任何官方参考。
我相信show bytecode的结果不是原始的Bytecode。这是因为原始的Bytecode不是人类可读的。
所以,作为Show bytecode的结果,类文件的反编译版本都是经过处理的形式。为什么两者之间会有差异呢?
(我也听说类文件是由字节码组成的)
这是由反编译过程和show bytecode过程之间的差异引起的问题吗?后者更有弹性?(猜测)

inb24sb2

inb24sb21#

为什么两者之间存在差异?
如果你问为什么“.class file”和“show bytecode result”之间存在差异,那是因为它们显示的是不同的东西:

  • 前者显示反编译器试图从字节码重构源代码。
  • 后者展示了字节码的反汇编;即,字节码呈现为(近似于)字节码汇编语言。这是为那些希望在JVM规范的帮助下1读取Java编译器输出的字节码的人设计的。

如果你问为什么“原始.java文件”和“.class文件”是不同的,它们(再一次)显示了不同的东西。

  • 前者显示您编写的Java源代码
  • 后者显示的是由反编译器生成的 * 重构 * Java代码。基本上,原始代码被编译成字节码,然后被 * 反编译 * 回Java源代码。这些代码可能正确,也可能不正确2。

在这种情况下,反编译代码与原始代码不同。看起来反编译器无法重建enum及其private int变量的构造函数。这是Intellij使用的反编译器的一个 * 限制 *。我想这个限制 * 可以 * 修复3。然而反编译器的限制是固有的,无法修复。这些限制包括:

  • 反编译器无法重构原始代码布局、javadoc、注解等“.class”文件中不存在的内容。
  • 如果两个不同的Java源代码构造编译为相同的字节码,反编译器无法分辨最初使用的是哪一个。
  • 字节码混淆器,故意对字节码做一些事情,使其更难重构有效的Java源代码......更不用说可读的代码了。

1 -这并不像你想象的那么有用。“问题”是字节码是(故意)不优化。相反,JIT编译器将(最终)编译并优化字节码为本地代码。通常JIT编译器执行的转换是相当激进的;例如内联方法,优化掉不必要的循环,这意味着您可能从阅读字节码中获得的所谓性能洞察(充其量)是不可靠的。
2 -它可能与原始代码在功能上不完全相同。实际上,它甚至可能不是有效的Java源代码。这有各种原因。
3 -...如果有人愿意投入工作。事实上,这个问题有可能已经在(假设的)更新版本的反编译器中得到了解决。

展开查看全部
b4wnujal

b4wnujal2#

正如FernFlower的评论所解释的,你所指的.class文件实际上是重新创建的源代码。.class文件通过反编译器运行,试图将字节码转换回其原始源代码。
您粘贴的“show bytecode result”代码只是文件内容的可读表示

相关问题