如何从AnyRef对象获取反映的运行时方法?

时间:2018-08-02 15:19:56

标签: scala reflection

我正在尝试在实例中获取反映的运行时方法,但未在decls结果中显示:

val foo: AnyRef = new Object {
  def bar = 1
}
typeOf[foo.type].decls //Does not contain bar method

我尝试使用Java反射类,并且可以正常工作:

foo.getClass.getDeclaredMethods //It contains bar method

但是我更喜欢使用MethodSymbols和Scala Type,而不是Java类和方法反射。如何获得反映的MethodSymbol?


我想要一个方法来查找作为方法栏的AnyRef传递的对象并对其进行调用。如下所示:

def getBarMethodFromObj(obj: AnyRef): MethodSymbol = {
  //typeOf(obj).decl(TermName("bar")) this doesn't work
}

我不能使用trait,因为bar可以具有不同的参数以及返回类型和数字。由于Scala不支持可变的泛型参数,因此我计划使用反射来查找方法和调用,但这在Scala中也无法做到。我目前正在使用Java解决方案:

val bar = foo.getClass.getDeclaredMethods.find(_.getName == "bar")
bar.invoke(foo, params: _*)

但是Java反射并不会保留泛型类型,因为它会为List和Map等带来问题。所以我想知道我是否可以在Scala中实现它,或者有什么解决方案

1 个答案:

答案 0 :(得分:6)

我不知道您要做什么,但是删除AnyRef注释可以使您的代码正常工作

val foo = new { def bar = 1 }
typeOf[foo.type].decls // Contains bar method

如果需要类型注释(例如,在方法签名中),则可以使用编译器推断的相同结构类型:

val foo: { def bar: Int } = new { def bar = 1 }

如果您想从其他方法获取方法的完整列表,而又不知道泛型以外的确切类型,那么您可能会对TypeTag感兴趣:

import scala.reflect.runtime.universe.{ TypeTag, typeTag }
val foo = new { def bar = 1 }
def getMethods[T: TypeTag](t: T) = typeTag[T].tpe.decls
getMethods(foo) // Contains bar

如果您不能使用TypeTag(也许是因为您无法更改API),那么最好使用Java Reflection API。 Scala反射API通常设计为使用类型信息,因此,如果您仅知道类型为AnyRef,它可能对您不起作用。


根据您的修改:

  

我不能使用特征,因为bar可以具有不同的参数以及返回类型和数字。

确定可以:

trait Foo[A, B] {
  def bar(a: A): B
}

如果需要多个参数,只需让bar取一个元组即可。如果您需要执行一些元组不支持的列表操作,则可以考虑了解HList和shapeless

  

但是Java反射不能保留通用类型...

好吧,仅运行时反射API不会为您提供帮助。根本无法找出运行时AnyRef具有哪些通用参数,因为JVM上不存在该信息。使用TypeTag,或以上述方式使用trait