我有一个class
,其中包含一些对象作为内部方法。
我前一段时间也问this question并得到了一个很好的答案,但这导致了servlet容器中的致命错误。当TypeTag
要求上课时,Scala无法始终生成URLClassLoader
。
有问题的项目是开源的,找到here。
找到当前方法here,但它不会保留顺序。对象成员已正确初始化,但是以随机顺序。
问题:如何收集班级成员:
module.instance
)
?更新:
val
代替object
。getMethods
或getDeclaredFields
已知不保证订单。如果这在某种程度上是可能的,那很可能是Scala的反思。答案 0 :(得分:5)
来自http://docs.oracle.com/javase/6/docs/api/java/lang/Class.html#getDeclaredFields():
public Field [] getDeclaredFields() 抛出SecurityException
返回Field对象的数组,反映类或接口声明的所有字段 由此Class对象表示。这包括公共,受保护,默认(包)访问,以及 私有字段,但不包括继承的字段。 返回的数组中的元素未排序 没有任何特定的顺序。如果类或接口,此方法返回长度为0的数组 声明没有字段,或者此Class对象表示基本类型,数组类或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)
}
}
请参阅the API docs:
对此范围中包含的符号进行排序,以便:1)符号以其所有者的线性化顺序显示。 2)具有相同所有者的符号以其声明的相同顺序出现。 3)合成成员(例如vals / vars的getter / setter)可能以任意顺序出现。
但是,这不能保证一般工作,特别是对于混合Java / Scala项目(因为实际上没有办法按声明顺序获取Java类的成员)。另外,请注意Scala运行时反射不是线程安全的,通常不被视为生产就绪。
我仍然觉得通过将设计修改为与顺序无关的方式可以更好地服务,可能是通过不同地编码依赖关系。
答案 1 :(得分:0)
AFAIK,这是不可能的。订单类成员的定义根本不会保存在.class
文件中(至少使用Java反射)。
答案 2 :(得分:0)
你有一个内部有object
个内容的课程。正如您所指出的,当其他一些代码引用/调用它们时,内部对象延迟初始化(类似于lazy val
)。
问题:(a)上述延迟初始化PLUS(b)隐式对象定义之间的相互依赖关系。这意味着它们需要按照它们的依赖链的顺序进行初始化,但是它们没有明确地相互引用,因此正确排序的延迟初始化不会自动发生。
尝试解决方案:通过在构建/初始化阶段使用反射,以正确的顺序以编程方式预初始化这些对象。虽然如果scala或java反射与你合作,这将有效,但它反对谷物' - 它与内部对象的定义相反。如果你不想让它们进行惰性初始化,那么为什么要首先将它们声明为内部对象呢?
我建议的解决方案:将声明从内部object
更改为val
s。根据所需的初始化顺序对这些声明进行排序。不需要反思。
(旁白:在此Q&相关内容中,您已经提到了必须使用object
的人为约束或原因。但是,如果有一些你必须使用对象的奇怪原因,然后你仍然可以避免反射。只需让每个对象的构造函数调用它所依赖的每个对象的方法forceInit
。每个forceInit
方法只能返回1这将以正确的顺序触发延迟初始化。)
: - )
答案 3 :(得分:0)
我遇到了类似的问题并使用了带有一些价值的注释来强制命令。特别是,我的对象模型驱动一个SWT表,所以我创建了:
public @interface DefaultColumnPosition {
int value();
}
然后使用@DefaultColumnPosition(0)
或任何数字注释字段。按值排序。有一点开销,如果有一个不同的方法,或者可能是强制订单但看起来不像它的类级别注释会更好。
没有尝试过Scala解决方案,但它看起来也很有趣,我可以试一试。