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
    getDeclaredFields
    不能保证订单。如果这在某种程度上是可能的,那么很可能是Scala反射

好吧,这是不可能的。在中定义的order类成员不会保留在
.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反射是否真的保证了顺序的保留?对我来说,这听起来像是