Reflection scala反射:getDeclaringTrait?

Reflection scala反射:getDeclaringTrait?,reflection,scala,Reflection,Scala,当我研究一个新的库时,我有时发现很难找到一个方法的实现 在Java中,Methodo#getDeclaringClass提供声明给定方法的类。因此,通过迭代类#getMethods,我可以找到每个方法的声明类 在Scala中,trait被转换为Java接口,扩展trait的类将通过将trait的方法转发给静态定义这些方法的同伴类来实现trait的方法。这意味着,该方法#getDeclaringClass将返回类,而不是trait: scala> trait A { def foo = {p

当我研究一个新的库时,我有时发现很难找到一个方法的实现

在Java中,Methodo#getDeclaringClass提供声明给定方法的类。因此,通过迭代类#getMethods,我可以找到每个方法的声明类

在Scala中,trait被转换为Java接口,扩展trait的类将通过将trait的方法转发给静态定义这些方法的同伴类来实现trait的方法。这意味着,该方法#getDeclaringClass将返回类,而不是trait:

scala> trait A { def foo = {println("hi")}}
defined trait A

scala> class B extends A
defined class B

scala> classOf[B].getMethods.find(_.getName() == "foo").get.getDeclaringClass
res3: java.lang.Class[_] = class B
解决这个问题的最佳方法是什么?也就是说,给定一个类,我如何才能得到一个列表[(方法,类)],其中每个元组都是一个方法和它声明的特征/类?

如果您的目标实际上是“研究一个新的库”,文档会提供这些信息。继承的方法(未被重写)在定义它们的继承类下列出并链接(仅它们的名称)


这还不足以理解图书馆吗?此外,每个文档页面都包含一个指向源代码的链接。

以下是一些有用的东西:

def methods(c: Class[_]): Array[String] = {
    val dm = try {
        val cls = if (c.isInterface) Class.forName(c.getName() + "$class") else c

        cls.getDeclaredMethods().map(m =>                            
            decode(c.getCanonicalName) + "#" + 
            decode(m.getName) + "(" + 
            {m.getParameterTypes.toList match {
                case h :: tail => tail.map{(c: Class[_]) => decode(c.getCanonicalName)}.mkString(",")
                case Nil => ""
            }} + "): " +    
            decode(m.getReturnType.getCanonicalName))
    } catch {case _ => Array[String]()}

    dm ++ c.getInterfaces.flatMap(methods(_))
}

你可以看到有一些过滤,可以做一些转换。
最烦人的是B有一个“hi”声明,因为它将调用转发给$class#hi。但是,这与B实际使用自己的实现覆盖“hi”的情况没有区别。

在Scala 2.8中,您可以使用ScalaSigParser来解析Scala特定的字节码信息

这将比scala特性、类和方法的字节码序列化格式更稳定

import tools.scalap.scalax.rules.scalasig._
import scala.runtime._

val scalaSig = ScalaSigParser.parse(classOf[RichDouble]).get
val richDoubleSymbol = scalaSig.topLevelClasses.head
val methods = richDoubleSymbol.children filter ( _ match {
    case m : MethodSymbol => true
    case _ => false
})

methods foreach println
richDoubleSymbol.isTrait
ScalaSigParser.parse(classOf[Ordered[Any]]).get.topLevelClasses.head.isTrait
印刷品:

scala> methods foreach println
MethodSymbol(x, owner=0, flags=20080004, info=23 ,None)
MethodSymbol(<init>, owner=0, flags=200, info=33 ,None)
[...]
MethodSymbol(isPosInfinity, owner=0, flags=200, info=117 ,None)
MethodSymbol(isNegInfinity, owner=0, flags=200, info=117 ,None)

scala> richDoubleSymbol.isTrait
res1: Boolean = false

scala> ScalaSigParser.parse(classOf[Ordered[Any]]).get.topLevelClasses.head.isTrait
res2: Boolean = true
scala>每个println的方法
MethodSymbol(x,所有者=0,标志=20080004,信息=23,无)
MethodSymbol(,所有者=0,标志=200,信息=33,无)
[...]
MethodSymbol(isPosInfinity,所有者=0,标志=200,信息=117,无)
MethodSymbol(isNegInfinity,所有者=0,标志=200,信息=117,无)
scala>richDoubleSymbol.isTrait
res1:Boolean=false
scala>ScalaSigParser.parse(classOf[Ordered[Any]]).get.topLevelClasses.head.isTrait
res2:Boolean=true

我想沿着这条路走下去,您可以为Scala构建一个反射API

您假设每个库都有很好的文档记录。此外,我的问题是关于一般的反思,而不是“我如何研究新图书馆”。这一部分是为了让人们不会开始问“你为什么需要这样的反思?”。确定你所问的事情(你在第一句话中确实说过你正在研究新的库)在源代码中以及Scaladoc HTML中都是可靠和完整的。此外,考虑到Scala和JVM之间关系的性质,通过源代码总是可以获得比字节码更多的信息。
scala> methods foreach println
MethodSymbol(x, owner=0, flags=20080004, info=23 ,None)
MethodSymbol(<init>, owner=0, flags=200, info=33 ,None)
[...]
MethodSymbol(isPosInfinity, owner=0, flags=200, info=117 ,None)
MethodSymbol(isNegInfinity, owner=0, flags=200, info=117 ,None)

scala> richDoubleSymbol.isTrait
res1: Boolean = false

scala> ScalaSigParser.parse(classOf[Ordered[Any]]).get.topLevelClasses.head.isTrait
res2: Boolean = true