问题 方法由javac在生成的类文件中排序


使用JDK7,反射API已经改变,现在getDeclaredMethods()返回的方法是  按照在源文件中声明它们的顺序返回。

现在我的问题是,javac生成的.class文件是否包含方法 以相同的顺序 它们是在源文件中定义的,还是可以按随机顺序编写方法?


3131
2017-12-24 09:01


起源

您可以通过再次编译和查看反编译代码轻松检查自己(使用反编译器) - vishal_aim
@vishal_aim - 是的,我已经做到了,对我来说也是如此。我更想知道它是否会在不同的jdk实现/平台上发生。 - Manish
从纯语言规范的角度来看,声明方法的顺序对程序没有任何影响,所以我看不到改变方法顺序的编译器是如何不符合的,因为程序可以正常工作同样的方式... - assylias
@assylias:问题是我有一个包含数千个junits的遗留代码库,其中一些依赖于它们执行的顺序。他们曾经使用JDK6(因为反射返回的方法与定义的顺序相同),但是间歇性地使用jdk7失败。 - Manish
@JoachimSauer:你是完全正确的。我同意他们编码错误,长期解决方案将是纠正测试用例,但我正在寻找一个更快的解决方案,只是为了让他们现在工作。 - Manish


答案:


Java语言规范的二进制兼容性章节 明确表示允许对类文件中的元素进行重新排序:

[...]这里列出了Java编程语言支持的一些重要的二进制兼容更改:

  • [...]

  • 重新排序现有类型声明中的字段,方法或构造函数。

  • [...]

  • 重新排序类或接口的直接超接口列表。

这意味着它们出现在.class文件中的顺序不是由规范决定的。如果你想依赖它,你必须要么(1)知道你的具体实现使用与定义顺序相同的顺序(测试它,就像你做的那样,是一个好主意,但不能保证任何东西) ),或(2)自己更改订单。


8
2017-12-24 09:21



“二进制兼容性”确实如此 不 必然意味着结果完全相同。它只表示针对旧版本编译的代码将继续使用较新版本(或至少加载/链接)。 - Joachim Sauer
@JoachimSauer我接受了这一点,但在我看来,可以推断出不同的编译器可以为同一个类生成具有不同方法顺序的类文件......我认为这些文件转换为“不受规范的支配”。 - Oak
我同意“没有口述”的部分,我只是不认为这一章是一个很好的论据。 - Joachim Sauer


Class.getDeclaredMethods API很清楚这个“...返回的数组中的元素没有排序,并且没有按任何特定的顺序......”。最有可能的原因是javac没有义务以任何特定顺序在.class中生成方法。


3
2017-12-24 09:28