为什么 Java class 编译时有一个空行?
Why does a Java class compile differently with a blank line?
我有以下Javaclass
public class HelloWorld {
public static void main(String []args) {
}
}
当我编译此文件并在生成的 class 文件上 运行 sha256 时,我得到
9c8d09e27ea78319ddb85fcf4f8085aa7762b0ab36dc5ba5fd000dccb63960ff HelloWorld.class
接下来我修改了 class 并添加了一个空行,如下所示:
public class HelloWorld {
public static void main(String []args) {
}
}
我再次 运行 输出上的 sha256 期望得到相同的结果,但我得到的是
11f7ad3ad03eb9e0bb7bfa3b97bbe0f17d31194d8d92cc683cfbd7852e2d189f HelloWorld.class
我在 this TutorialsPoint article 上读到:
A line containing only white space, possibly with a comment, is known as a blank line, and Java totally ignores it.
所以我的问题是,由于 Java 忽略空行,为什么两个程序的编译字节码不同?
即区别在于 HelloWorld.class
中的 0x03
字节被 0x04
字节替换。
基本上,行号是为了调试而保留的,所以如果您按照原来的方式更改源代码,您的方法将从不同的行开始,编译后的 class 会反映出差异。
您可以使用 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:
更准确地说,class 文件在 LineNumberTable
部分有所不同:
The LineNumberTable attribute is an optional variable-length attribute in the attributes table of a Code attribute (§4.7.3). It may be used by debuggers to determine which part of the code array corresponds to a given line number in the original source file.
If multiple LineNumberTable attributes are present in the attributes table of a Code attribute, then they may appear in any order.
There may be more than one LineNumberTable attribute per line of a source file in the attributes table of a Code attribute. That is, LineNumberTable attributes may together represent a given line of a source file, and need not be one-to-one with source lines.
除了用于调试的任何行号详细信息外,您的清单还可能存储构建时间和日期。这个自然每次编译都不一样
"Java ignores blank lines"的假设是错误的。这是一个代码片段,根据方法 main
:
之前的空行数,其行为会有所不同
class NewlineDependent {
public static void main(String[] args) {
int i = Thread.currentThread().getStackTrace()[1].getLineNumber();
System.out.println((new String[]{"foo", "bar"})[((i % 2) + 2) % 2]);
}
}
如果main
之前没有空行,则打印"foo"
,但main
之前有一个空行,则打印"bar"
.
由于运行时行为不同,.class
文件 必须 不同,无论任何时间戳或其他元数据如何。
这适用于所有可以访问带行号的堆栈帧的语言,不仅适用于 Java。
注意:如果使用-g:none
编译(没有任何调试信息),则不会包含行号,getLineNumber()
总是returns -1
,并且该程序总是打印 "bar"
,而不管换行符的数量。
我有以下Javaclass
public class HelloWorld {
public static void main(String []args) {
}
}
当我编译此文件并在生成的 class 文件上 运行 sha256 时,我得到
9c8d09e27ea78319ddb85fcf4f8085aa7762b0ab36dc5ba5fd000dccb63960ff HelloWorld.class
接下来我修改了 class 并添加了一个空行,如下所示:
public class HelloWorld {
public static void main(String []args) {
}
}
我再次 运行 输出上的 sha256 期望得到相同的结果,但我得到的是
11f7ad3ad03eb9e0bb7bfa3b97bbe0f17d31194d8d92cc683cfbd7852e2d189f HelloWorld.class
我在 this TutorialsPoint article 上读到:
A line containing only white space, possibly with a comment, is known as a blank line, and Java totally ignores it.
所以我的问题是,由于 Java 忽略空行,为什么两个程序的编译字节码不同?
即区别在于 HelloWorld.class
中的 0x03
字节被 0x04
字节替换。
基本上,行号是为了调试而保留的,所以如果您按照原来的方式更改源代码,您的方法将从不同的行开始,编译后的 class 会反映出差异。
您可以使用 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:
更准确地说,class 文件在 LineNumberTable
部分有所不同:
The LineNumberTable attribute is an optional variable-length attribute in the attributes table of a Code attribute (§4.7.3). It may be used by debuggers to determine which part of the code array corresponds to a given line number in the original source file.
If multiple LineNumberTable attributes are present in the attributes table of a Code attribute, then they may appear in any order.
There may be more than one LineNumberTable attribute per line of a source file in the attributes table of a Code attribute. That is, LineNumberTable attributes may together represent a given line of a source file, and need not be one-to-one with source lines.
除了用于调试的任何行号详细信息外,您的清单还可能存储构建时间和日期。这个自然每次编译都不一样
"Java ignores blank lines"的假设是错误的。这是一个代码片段,根据方法 main
:
class NewlineDependent {
public static void main(String[] args) {
int i = Thread.currentThread().getStackTrace()[1].getLineNumber();
System.out.println((new String[]{"foo", "bar"})[((i % 2) + 2) % 2]);
}
}
如果main
之前没有空行,则打印"foo"
,但main
之前有一个空行,则打印"bar"
.
由于运行时行为不同,.class
文件 必须 不同,无论任何时间戳或其他元数据如何。
这适用于所有可以访问带行号的堆栈帧的语言,不仅适用于 Java。
注意:如果使用-g:none
编译(没有任何调试信息),则不会包含行号,getLineNumber()
总是returns -1
,并且该程序总是打印 "bar"
,而不管换行符的数量。