2017-10-19 74 views

回答

2

在使用Scala Reflection API時,如果您使用了Java反射API,您會遇到更多類型的用法。鑑於你開始用含有類的完全限定類名稱的String的示例場景,這些都是你很可能會遇到類型:

  • Universe:斯卡拉支持運行時和編譯時反射。通過從相應的Universe導入,您可以選擇您正在進行的反射。對於運行時反射,這對應於scala.reflect.runtime包,對於編譯時反射它對應於scala.reflect.macros包。這個答案關注前者。

    與Java一樣,您通常會通過選擇要反映的ClassLoader的類來啓動任何反射。 Scala提供了一個使用當前類的ClassLoader的快捷方式:scala.reflect.runtime.currentMirror,這會給你一個Mirror(稍後的更多鏡像)。許多JVM應用程序只使用一個類加載器,所以這是Scala Reflection API的一個常用入口點。由於您從runtime導入,您現在處於該宇宙中。

  • Symbols:符號包含關於您想要反映的任何靜態元數據。這包括任何你能想到的:這是一個case類,它是一個字段,是一個類,什麼是類型參數,是抽象的等等。你可能不會查詢任何可能依賴於當前詞法範圍的東西,例如一個班級有什麼成員。您也可能無法以任何方式與您反思的內容進行交互(如訪問字段或調用方法)。你可以查詢元數據。

    一個班級的成員如何隨詞彙範圍而變化?想象一下帶有單個def foo: String的抽象類。名稱foo可能在一個上下文中綁定到def(如果您查詢它,則會給出MethodSymbol),或者可能在另一個上下文(給出TermSymbol)時將其綁定到val。當使用符號的工作是很常見明確必須聲明你期待什麼樣的符號,你通過這些方法.asTerm.asMethod.asClass

    繼續,我們開始與String例子做到這一點。您可以使用Mirror推導出描述類的ClassSymbolcurrentMirror.staticClass(myString)

  • Types:類型允許您查詢有關符號在當前詞彙上下文中引用的類型的信息。您通常使用Type來做兩件事:查詢哪些變量,vals和defs,以及查詢類型關係(例如,此類型是該類型的子類)。有兩種方法可以獲得Type。通過TypeSymbolClassSymbolTypeSymbol)或通過TypeTag

    繼續這個例子,你將調用.toType方法來得到Type的符號。

  • Scopes:當你問一個Type.members.decl - 這是什麼讓你條件(VAR和丘壑)和方法,你得到的Symbol S中的成員在當前詞法範圍的列表。此列表保存在MemberScope類型中,它只是一個榮耀的List[Symbol]

    在我們上面的抽象類的示例中,取決於當前範圍,此列表將包含名稱fooTermSymbolMethodSymbol

  • Names:名稱有兩種口味:TermNameTypeName。它只是一個String的包裝。您可以使用該類型來確定由任何Name命名的內容。
  • Mirrors:最後鏡子是你用來與「某物」交互的東西。您通常從Symbol開始,然後使用該符號爲要與之交互的方法,構造函數或字段派生符號。當你有你需要的符號時,你使用currentMirror爲這些符號創建鏡像。通過鏡像,您可以調用構造函數(ClassMirror),訪問字段(FieldMirror)或調用方法(MethodMirror)。您不能使用鏡像來查詢關於所反映事物的元數據。

所以把一個例子一起反映上面的描述中,這是你如何將搜索領域,調用構造函數和閱讀val,給出完全限定類名String

// Do runtime reflection on classes loaded by current ClassLoader 
val currentMirror: universe.Mirror = scala.reflect.runtime.currentMirror 

// Use symbols to navigate to pick out the methods and fields we want to invoke 
// Notice explicit symbol casting with the `.as*` methods. 
val classSymbol: universe.ClassSymbol = currentMirror.staticClass("com.example.Foo") 
val constructorSymbol: universe.MethodSymbol = classSymbol.primaryConstructor.asMethod 
val fooSymbol: Option[universe.TermSymbol] = classSymbol.toType.members.find(_.name.toString == "foo").map(_.asTerm) 

// Get mirrors for performing constructor and field invocations 
val classMirror: universe.ClassMirror = currentMirror.reflectClass(classSymbol) 
val fooInstance: Foo = classMirror.reflectConstructor(constructorSymbol).apply().asInstanceOf[Foo] 
val instanceMirror: universe.InstanceMirror = currentMirror.reflect(fooInstance) 

// Do the actual invocation 
val fooValue: String = instanceMirror.reflectField(fooSymbol.get).get.asInstanceOf[String] 
println(fooValue) // Prints the value of the val "foo" of the object "fooInstance"