为什么 Java 类的编译方式与空行不同?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/52625161/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why does a Java class compile differently with a blank line?
提问by KNejad
I have the following Java class
我有以下 Java 类
public class HelloWorld {
public static void main(String []args) {
}
}
When I compile this file and run a sha256 on the resulting class file I get
当我编译这个文件并在生成的类文件上运行 sha256 时,我得到
9c8d09e27ea78319ddb85fcf4f8085aa7762b0ab36dc5ba5fd000dccb63960ff HelloWorld.class
Next I modified the class and added a blank line like this:
接下来我修改了类并添加了一个这样的空行:
public class HelloWorld {
public static void main(String []args) {
}
}
Again I ran a sha256 on the output expecting to get the same result but instead I got
我再次在输出上运行 sha256 期望得到相同的结果,但我得到了
11f7ad3ad03eb9e0bb7bfa3b97bbe0f17d31194d8d92cc683cfbd7852e2d189f HelloWorld.class
I have read on this TutorialsPoint articlethat:
我已经阅读了这篇 TutorialsPoint 文章:
A line containing only white space, possibly with a comment, is known as a blank line, and Java totally ignores it.
仅包含空格(可能带有注释)的行称为空行,Java 完全忽略它。
So my question is, since Java ignores blank lines why is the compiled bytecode different for both programs?
所以我的问题是,既然 Java 忽略了空行,为什么两个程序的编译字节码不同?
Namely the difference in that in HelloWorld.class
a 0x03
byte is replaced by a 0x04
byte.
即HelloWorld.class
一个0x03
字节中的差异被一个0x04
字节代替。
采纳答案by Federico klez Culloca
Basically, line numbers are kept for debugging, so if you change your source code the way you did, your method starts at a different line and the compiled class reflects the difference.
基本上,行号是为了调试而保留的,因此如果您按照自己的方式更改源代码,您的方法会从不同的行开始,并且编译后的类会反映差异。
回答by Karol Dowbecki
You can see the change by using javap -v
which will output verbose information. Like other already mentioned the difference will be in line numbers:
您可以通过使用javap -v
which 将输出详细信息来查看更改。像其他已经提到的不同之处在于行号:
$ 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:
More precisely the class file differs in the LineNumberTable
section:
更准确地说,类文件在以下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.
LineNumberTable 属性是 Code 属性(第 4.7.3 节)的属性表中的可选可变长度属性。调试器可以使用它来确定代码数组的哪一部分对应于原始源文件中的给定行号。
如果代码属性的属性表中存在多个 LineNumberTable 属性,则它们可以按任意顺序出现。
在 Code 属性的属性表中,源文件的每一行可能有多个 LineNumberTable 属性。也就是说, LineNumberTable 属性可以一起表示源文件的给定行,并且不需要与源行一一对应。
回答by Graham
As well as any line number details for debugging, your manifest may also store the build time and date. This will naturally be different every time you compile.
除了用于调试的任何行号详细信息外,您的清单还可以存储构建时间和日期。每次编译时,这自然会有所不同。
回答by Andrey Tyukin
The assumption that "Java ignores blank lines"is wrong. Here is a code snippet that behaves differently depending on the number of empty lines before the method main
:
“Java 忽略空行”的假设是错误的。这是一个代码片段,其行为取决于方法之前的空行数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]);
}
}
If there are no empty lines before main
, it prints "foo"
, but with one empty line before main
, it prints "bar"
.
如果前面没有空行main
,则打印"foo"
,但如果前面有一个空行main
,则打印"bar"
。
Since the runtime behavior is different, the .class
files mustbe different, regardless of any timestamps or other metadata.
由于运行时行为不同,.class
文件必须不同,无论时间戳或其他元数据如何。
This holds for every language that has access to the stack frames with line numbers, not only for Java.
这适用于可以访问带有行号的堆栈帧的每种语言,不仅适用于 Java。
Note: if it's compiled with -g:none
(without any debugging information), then the line numbers will not be included, getLineNumber()
always returns -1
, and the program always prints "bar"
, regardless of the number of line breaks.
注意:如果它是用-g:none
(没有任何调试信息)编译的,那么行号将不包括在内,getLineNumber()
总是返回-1
,并且程序总是打印"bar"
,无论换行数多少。