斯卡拉反思:为什么可以的getMethods返回VAL成员?(Scala Reflection :

2019-10-22 18:34发布

在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文档,

公共方法[]的getMethods()抛出抛出:SecurityException返回一个包含反射的类或接口的该Class对象表示所有的公共成员方法,包括那些由类或接口和那些从超类和超接口继承的声明的方法对象的数组

Answer 1:

Java不知道val秒。 val s为Scala的构建,而不是Java的构建。 人机工程学,Java反射不能左右返回任何val ,因为没有这样的东西val在Java中。 最接近的事到斯卡拉val在Java是一个getter方法,而这正是如何斯卡拉val s的在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)


Answer 2:

除了@JorgW¯¯米塔格答案。 你可以编译Scala代码,然后分析结果类与Java反编译。 例如。 这里是唯一的斯卡拉类val

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(); 类名后面的方法。



文章来源: Scala Reflection : why getMethods can return the val members?