我正在寻找一种按源顺序检索(在运行时)类的字段的方法,以便我可以执行自己的“初始化处理”,该处理基于声明的顺序。我知道 Javadoc 用于Class.getDeclaredFields()
明确指出不保证订单。
SO 上的一些答案指向Javassist
但我找不到任何证据表明javassist
在没有行号信息的情况下有任何此类保证。
然而 Java 编译器使用了这种“源代码顺序”,因为此代码无法编译:
private int a = 10 * b;
private int b = 5;
显然,价值b
目前尚不清楚a
正在宣布。
这个初始化顺序也必须出现在字节码中,因为在运行时初始化必须以相同的顺序发生(当然,这只是这些边缘情况的要求:-(但这让我认为自然的事情是存储里面的源顺序.class
file.
问题:
JVM/字节代码如何按照声明的顺序初始化成员字段,这些信息是否可以用于重建字段的源顺序?
有没有其他有保证的方法可以实现同样的目标。像Javassist这样的第三方工具是可以的,但它必须是“有保证的”或者至少是“在特定条件下有保证”。
是否有任何特定的 Java 实现可以保证顺序Class.getDeclaredFields()
(也许在特定条件下(哪些条件))?
供您参考,我需要源顺序来重建顺序很重要的遗留语言的行为。我不喜欢明确添加订单,例如通过添加数组或注释,因为我想保持源代码尽可能可读。
- 编辑 -
一个重要的注意事项可能是我需要“遍历”的字段都将被注释,例如@MyComplexType(len = 4)
。父类将需要此元信息来构造一种内存映射。然而,我不想让这个注释与订购信息混淆,因为我发现这会妨碍可读性和可维护性。
关于你的第二个问题和第三个问题,只能使用一种肮脏的黑客方法按顺序检索字段:
在字节码中,类文件的字段和方法都不是按顺序存储的。我不知道why情况确实如此(尽管我制作了自己的 JVM 编译器),但我相信 Java 编译器只是决定这样做。Class.getDeclaredFields
按照从字节码读取字段的顺序返回字段,这就是为什么它声明不保证顺序。
如果您仍然想让它们按顺序排列,我会尝试以下操作:您使用字节码解析器库(例如 Javassist 或 ASM)来读取类文件,并跳过除构造函数(以及static {}
如果您还想对静态字段进行排序)。一旦你遇到一个PUTFIELD
or PUTSTATIC
指令的owner
是您正在检查的类,您可以通过字节码中存储的调试信息获取可用的当前行,并使用它对字段进行排序。这种技术的问题是效率低下,而且它依赖于行号属性,而这些属性并不总是存在于类文件中。此外,你只会发现PUT*
显式初始化字段的说明,默认字段,例如
protected int modifiers;
未由编译器初始化,因此字节码中没有可用的指令和行号信息。在这种情况下,或者当一般没有 LineNumber 属性时,您很不幸地运气不好。此时,我能想到的唯一解决方案就是阅读该类的实际源代码。
根据您尝试检查的类,您可能无法获取该类的实际字节码,但这本身就是一个问题。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)