为什么 Java 类使用空行以不同的方式编译?

2022-08-31 06:04:34

我有以下Java类

public class HelloWorld {
  public static void main(String []args) {
  }
}

当我编译这个文件并在我得到的结果类文件上运行sha256时

9c8d09e27ea78319ddb85fcf4f8085aa7762b0ab36dc5ba5fd000dccb63960ff  HelloWorld.class

接下来,我修改了类并添加了一个空行,如下所示:

public class HelloWorld {

  public static void main(String []args) {
  }
}

我再次在输出上运行了sha256,期望得到相同的结果,但相反,我得到了

11f7ad3ad03eb9e0bb7bfa3b97bbe0f17d31194d8d92cc683cfbd7852e2d189f  HelloWorld.class

我在本教程Point文章中读到:

仅包含空格(可能带有注释)的行称为空行,Java 完全忽略它。

所以我的问题是,既然Java忽略了空行,为什么编译后的字节码对于两个程序都不同?

也就是说,字节中的差异被字节替换。HelloWorld.class0x030x04


答案 1

基本上,保留行号是为了进行调试,因此,如果您以自己的方式更改源代码,则方法将从不同的行开始,并且编译的类会反映差异。


答案 2

您可以通过使用它将输出详细信息来查看更改。像其他已经提到的一样,差异将在行号上:javap -v

$ javap -v HelloWorld.class > with-line.txt
$ javap -v HelloWorld.class > no-line.txt
$ diff -C 1 no-line.txt with-line.txt
*** no-line.txt 2018-10-03 11:43:32.719400000 +0100
--- with-line.txt       2018-10-03 11:43:04.378500000 +0100
***************
*** 2,4 ****
    Last modified 03-Oct-2018; size 373 bytes
!   MD5 checksum 058baea07fb787bdd81c3fb3f9c586bc
    Compiled from "HelloWorld.java"
--- 2,4 ----
    Last modified 03-Oct-2018; size 373 bytes
!   MD5 checksum 435dbce605c21f84dda48de1a76e961f
    Compiled from "HelloWorld.java"
***************
*** 50,52 ****
        LineNumberTable:
!         line 3: 0
        LocalVariableTable:
--- 50,52 ----
        LineNumberTable:
!         line 4: 0
        LocalVariableTable:

更准确地说,类文件在 LineNumberTable 部分中有所不同:

LineNumberTable 属性是 Code 属性 (§4.7.3) 的属性表中的可选可变长度属性。调试器可以使用它来确定代码数组的哪个部分对应于原始源文件中的给定行号。

如果 Code 属性的属性表中存在多个 LineNumberTable 属性,则它们可以按任意顺序显示。

在 Code 属性的属性表中,源文件的每行可能有多个 LineNumberTable 属性。也就是说,LineNumberTable 属性可以一起表示源文件的给定行,而不必与源行一对一。


推荐