Java/Scala反射:按顺序获取类方法并强制对象初始化
我有一个Java/Scala反射:按顺序获取类方法并强制对象初始化,java,scala,reflection,phantom-dsl,Java,Scala,Reflection,Phantom Dsl,我有一个类,有几个对象作为内部方法 我刚才也问了,得到了一个很好的答案,但这会导致servlet容器中出现致命错误。当URLClassLoader请求类时,Scala无法一致地生成TypeTag 所讨论的项目是开源的 找到了当前的方法,但它不能保持秩序。对象成员已正确初始化,但顺序是随机的 问题:如何收集班级成员: 按照定义的顺序 以线程安全的方式 按超级类型筛选它们 并初始化对象(引用module.instance) ? 更新: 不要根据此处的链接建议答案,它们已经过测试,并且已知失败
类
,有几个对象作为内部方法
我刚才也问了,得到了一个很好的答案,但这会导致servlet容器中出现致命错误。当URLClassLoader
请求类时,Scala无法一致地生成TypeTag
所讨论的项目是开源的
找到了当前的方法,但它不能保持秩序。对象成员已正确初始化,但顺序是随机的
问题:如何收集班级成员:
- 按照定义的顺序
- 以线程安全的方式
- 按超级类型筛选它们
- 并初始化对象(引用
) ?module.instance
- 不要根据此处的链接建议答案,它们已经过测试,并且已知失败
- 出于风格上的原因,使用
而不是val
不是一个选项object
- 已知
或getMethods
不能保证订单。如果这在某种程度上是可能的,那么很可能是Scala反射getDeclaredFields
.class
文件中(至少使用Java反射)。来自:
公共字段[]getDeclaredFields()
抛出SecurityException
返回反映类或接口声明的所有字段的字段对象数组
由该类对象表示。这包括公共、受保护、默认(包)访问和
私有字段,但不包括继承的字段返回的数组中的元素未排序且
没有任何特定顺序。如果类或接口
声明没有字段,或者该类对象表示基元类型、数组类或void。
请参阅Java语言规范,第8.2节和第8.3节
(我的重点)。类似的语言在getDeclaredMethods()的文档中显式出现,但在getDeclaredClasses()的文档中却没有(但可以认为IMO是隐式的)
因此,不能依赖于JVM上Java反射的排序;在实践中,我已经看到顺序根据运行的JVM的体系结构而有所不同(32位与64位)
如果您确实必须按特定顺序初始化对象(为什么?),那么可以使用命名约定并手动排序;但是,最好将代码更改为与顺序无关
更新
您似乎可以从Scala反射API中获得一些信息:
trait EarlyInit {
val mirror = runtimeMirror(this.getClass.getClassLoader)
val reflection = mirror.reflect(this)
mirror
.classSymbol(this.getClass)
.toType
.members
.sorted /// This method is documented to return members "in declaration order"
.filter(_.isModule)
.foreach(m => reflection.reflectModule(m.asModule).instance)
}
}
见:
对包含在此范围内的符号进行排序,以便:1)符号按其所有者的线性化顺序显示。2) 具有相同所有者的符号按其声明的相同顺序出现。3) 合成成员(例如VAL/VAR的getter/setter)可能以任意顺序出现
但是,这不能保证在一般情况下起作用,特别是对于混合Java/Scala项目(因为实际上没有办法按声明顺序获取Java类的成员)。另外,请注意Scala运行时反射不是线程安全的,通常不被认为是生产就绪的
我仍然认为,如果将设计修改为与顺序无关,可能通过对依赖项进行不同的编码,会更好地为您服务。您有一个包含一些内部
对象的类。正如您所指出的,当一些其他代码引用/调用内部对象时(类似于lazy val
),内部对象将被延迟初始化
问题:(a)上述惰性初始化加上(b)对象定义之间的隐式相互依赖关系。这意味着它们需要按照依赖链的顺序进行初始化,但它们并不显式地相互引用,因此正确排序的惰性初始化不会自动发生
尝试的解决方案:在构造/初始化阶段使用反射,以正确的顺序以编程方式预先初始化这些对象。如果scala或java反射与您一起工作,这将是可行的,但它“与粒度背道而驰”——它的工作方式与内部对象的定义背道而驰。如果您不希望它们是惰性初始化的,那么为什么首先要将它们声明为内部对象呢
我建议的解决方案:将声明从内部object
s更改为val
s。根据所需的初始化顺序对这些声明进行排序。不需要思考
(旁白:在这个问题和相关问题中,您没有提到必须使用object
s的任何人为约束或原因。但是,如果必须使用object有一些奇怪的原因,那么您仍然可以避免反射。只需让每个对象的构造函数调用它所依赖的每个对象的方法forceInit
每个forceInit
方法只能返回1。这将以正确的顺序触发延迟初始化。)
:-)我遇到了一个类似的问题,并使用了一些有价值的注释来强制执行订单。特别是,我的对象模型驱动SWT表,因此我创建了:
public @interface DefaultColumnPosition {
int value();
}
然后用@DefaultColumnPosition(0)
或任何数字对字段进行注释。按值排序。这会有一点开销,如果有一个不同的方法,或者可能有一个类级别的注释来强制执行顺序,但看起来不像,那就更好了
我没有尝试过Scala解决方案,但它看起来也很有趣,我可以试一试。使用Scala反射非常简单。然而,这就带来了类型标签问题。@flavian,Scala反射是否真的保证了顺序的保留?对我来说,这听起来像是