Scala Reflection:为什么getMethods可以返回val成员?

时间:2015-04-21 08:03:04

标签: java scala reflection

在Scala中,我有Abstract Class

abstract class AbstractSQLParser {

  def apply(input: String): Int = {

    println(reserveWords)
    return 1
  }

  protected case class Keyword(str: String)
  // use Reflection here
  protected lazy val reserveWords: Int =
      this.getClass
          .getMethods
          .filter(_.getReturnType == classOf[Keyword])
          .length
}

另一个扩展了它:

class SqlParserDemo extends AbstractSQLParser{

  def apply(input: String, onError: Boolean) : Int = {

    apply(input)
  }

  protected val CREATE = Keyword("CREATE")
  protected val TEMPORARY = Keyword("TEMPORARY")
  protected val TABLE = Keyword("TABLE")
  protected val IF = Keyword("IF")
  protected val NOT = Keyword("NOT")
  protected val EXISTS = Keyword("EXISTS")

  def func1 = Keyword("HI")
}

但是当我打电话时

val sqlParser = new SqlParserDemo
print(sqlParser.apply("hello", false))

输出是:

  

7

     

1

令我困惑的是:为什么getMethods可以返回val成员?

你知道,在子课程中,我有 val一个功能。

在Oracle doc中,

  

public Method [] getMethods()                       throws SecurityException返回一个包含反映其所有公共成员方法的Method对象的数组   此Class对象表示的类或接口,包括   类或接口声明的那些以及从中继承的那些   超类和超接口

2 个答案:

答案 0 :(得分:2)

Java并不了解valval是Scala构造,而不是Java构造。因此,Java反射不能返回val的任何内容,因为Java中没有val这样的东西。 Java中Scala val最接近的是一个getter方法,这正是Scala val在Java端表示的方式,这正是您使用Java反射而不是斯卡拉反思。

如果您使用Scala反射,则会得到以下内容:

import scala.reflect.runtime.{universe => ru}

def getTypeTag[T: ru.TypeTag](obj: T) = ru.typeTag[T]

val theType = getTypeTag(sqlParser).tpe
theType.declarations
// => reflect.runtime.universe.MemberScope = 
//      SynchronizedOps(
//        constructor SqlParserDemo, 
//        value CREATE, 
//        value CREATE, 
//        value TEMPORARY, 
//        value TEMPORARY, 
//        value TABLE, 
//        value TABLE, 
//        value IF, 
//        value IF, 
//        value NOT, 
//        value NOT, 
//        value EXISTS, 
//        value EXISTS, 
//        method func1)

答案 1 :(得分:1)

除了@Jorg W Mittag的答案。您可以编译Scala代码,然后使用Java反编译器分析生成的类。例如。这是带有val唯一的Scala类:

class Test {
    val test = 5;
}

编译它,在反编译时你得到:

public class Test
{
   private final int test = 5;
   public int test() { return this.test; }
}

Java反射找到的是Scala编译器生成的合成方法,用于将val添加到JVM中。
或者,如果您更喜欢检查字节码:

.../Workspace/Scala/TestVal>javap -c Test
Compiled from "Test.scala"
public class Test {
  public int test();
    Code:
       0: aload_0
       1: getfield      #13                 // Field test:I
       4: ireturn

  public Test();
    Code:
       0: aload_0
       1: invokespecial #19// Method java/lang/Object."<init>":()V
       4: aload_0
       5: iconst_5
       6: putfield      #13                 // Field test:I
       9: return
}

在课程名称后面立即查看public int test();方法。