繁体   English   中英

.java中的注释更改.class文件的ByteCode

[英]Comments in .java change ByteCode of .class file

我的理解是Java编译器在输出.class文件中的字节码中不包含注释。

但是我有代码:

InputStream stream = getClassLoader().getResourceAsStream(classAsPath);
byte[] classBytes = IOUtils.toByteArray(stream);

我为我的java类运行它,为java代码添加注释,然后重新运行它。 我看到classBytes与添加的注释不同

注释不包含在类文件中。 但是,编译器默认包含一些用于调试目的的元数据,其中包括行号。 如果您的注释跨越一行或更多,这显然会更改所有内容的行号,因此生成的类文件将更改。

您可以将-g:none传递给javac以避免包含行号和其他可选元数据。

没有保证相同的源代码产生完全相同的字节代码。 该标准没有强制要求某些语言结构如何映射到字节代码结构,并且某些“最佳实践”随着时间的推移而发生了变化,或者在编译器实现之间有所不同。 某些方面,例如类文件中方法的顺序被认为是完全不相关的,并且可能是编译器的某些实现特定方面的结果,而不是故意的决定。

通常,使用完全相同的编译器实现和版本将重现相同的字节代码,因为编译器的程序代码是确定性的,但不必如此,例如一些哈希映射实现具有随机化功能,编译器也可以使用并行处理这可能会增加与结果无关的方面的不确定性。

鉴于即使完全相同的源代码也不能保证生成相同的字节码,即使很小的,实际上无关的更改也可能导致字节码的差异,因为即使没有其他更改,它们也可能对时序或哈希码产生影响。 。

正如其他人所说,插入注释行可能会更改默认包含的调试属性中的行号,因此这是获取不同字节代码的简单原因。 但重要的是要理解你总是得到相同的字节码的假设是根本上有缺陷的。

请注意,类似的错误假设已经导致Java API中的主要设计缺陷。 默认的serialVersionUID是通过散列类数据计算的,这些数据实际上与序列化数据的兼容性无关。 正如Serializable的文档所述:

如果可序列化类未显式声明serialVersionUID,则序列化运行时将基于类的各个方面计算该类的默认serialVersionUID值,如Java(TM)对象序列化规范中所述。 但是, 强烈建议所有可序列化类显式声明serialVersionUID值,因为默认的serialVersionUID计算对类细节高度敏感,这些细节可能因编译器实现而异,因此在反序列化期间可能导致意外的InvalidClassExceptions

不要重复这个错误。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM