2017-10-19 11 views

답변

2

스칼라 리플렉션 API로 작업 할 때 Java Reflection API를 사용한 경우 익숙한 유형이 훨씬 많습니다. 당신은 클래스의 정규화 된 클래스 이름을 포함하는 String로 시작 예제 시나리오 감안할 때, 이러한 발생할 가능성이있는 유형은 다음과 같습니다

  • Universe : 스칼라는 두 런타임을 지원하며, 시간의 반사를 컴파일합니다. 해당 유니버스에서 가져 와서 수행중인 리플렉션의 종류를 선택합니다. 런타임 리플렉션의 경우 이것은 scala.reflect.runtime 패키지에 해당하며 컴파일 시간 반영을 위해서는 scala.reflect.macros 패키지에 해당합니다. 이 대답은 전자에 초점을 맞 춥니 다.

    Java와 마찬가지로 일반적으로 어떤 ClassLoader 클래스를 반영할지 선택하여 반성을 시작합니다. 스칼라는 현재 클래스의 ClassLoader을 사용하기위한 지름길을 제공합니다 : scala.reflect.runtime.currentMirror, Mirror (나중에 미러에 대한 자세한 내용)을 제공합니다. 많은 JVM 응용 프로그램은 단 하나의 클래스 로더 만 사용하므로 Scala Reflection API의 일반적인 시작점입니다. runtime에서 가져 오기 때문에 이제 해당 유니버스에 있습니다.

  • Symbols : 기호에는 반영하고 싶은 내용에 대한 정적 메타 데이터가 포함되어 있습니다. 이것은 당신이 생각할 수있는 모든 것을 포함합니다.이 것은 사례 클래스, 필드, 클래스, 형식 매개 변수, 추상 등입니다. 현재 어휘 범위에 의존 할 수있는 것은 쿼리 할 수 ​​없습니다 , 예를 들어 클래스에 속한 멤버. 필드에 액세스하거나 메소드를 호출하는 것과 같이 어떤 식 으로든 반영하는 것과 상호 작용하지 않을 수도 있습니다. 메타 데이터를 쿼리 할 수 ​​있습니다.

    클래스의 멤버는 어휘 범위에 따라 어떻게 다릅니 까? 하나의 추상 클래스 인 def foo: String을 상상해보십시오. foo이라는 이름은 def에 바인드 될 수 있으며 (MethodSymbol은 쿼리해야 함) 다른 문맥에서는 val에 바인드 될 수 있습니다 (TermSymbol). 기호로 작업 할 때 명시 적으로 예상 상징의 종류를 명시해야하는 것이 일반적이다, 당신은 우리가 시작 String 예를 계속 방법 .asTerm, .asMethod, .asClass

    을 통해이 작업을 수행. Mirror을 사용하여 currentMirror.staticClass(myString) 클래스를 설명하는 ClassSymbol을 파생시킵니다.

  • Types : 유형을 사용하면 기호가 현재 어휘 문맥에서 참조하는 유형에 대한 정보를 조회 할 수 있습니다. 일반적으로 Type을 두 가지 용도로 사용합니다. 즉, 어떤 vars, val 및 def가 있는지 쿼리하고 유형 관계를 쿼리하는 것입니다 (예 :이 유형이 해당 유형의 하위 클래스 임). Type을 잡는 방법에는 두 가지가 있습니다. TypeSymbol (ClassSymbolTypeSymbol) 또는 TypeTag입니다.

    예를 계속하면 심볼 .toTypeType으로 가져와야합니다.

  • Scopes : 당신이 .members 또는 .decl -이에 대한 Type을 물어 보면 당신이 용어 (바르 및 발스)와주는 것입니다 방법을-현재 어휘 범위 내에서 회원의 Symbol의 목록을 얻을. 이 목록은 MemberScope 유형으로 유지되며, 이는 단지 영광을 얻은 List[Symbol]입니다.

    위의 추상 클래스의 예에서이 목록에는 현재 범위에 따라 foo 이름의 TermSymbol 또는 MethodSymbol이 포함됩니다.

  • Names : TermNameTypeName : 이름은 두 가지 종류로 왔습니다. 그것은 단지 String의 래퍼입니다. 유형을 사용하여 이름이 Name 인 것을 판별 할 수 있습니다.
  • Mirrors : 마지막으로 미러는 "무언가"와 상호 작용하는 데 사용됩니다. 일반적으로 Symbol으로 시작한 다음 해당 기호를 사용하여 상호 작용하려는 메서드, 생성자 또는 필드의 심볼을 가져옵니다. 필요한 기호가 있으면 currentMirror을 사용하여 기호에 대한 거울을 작성하십시오. 미러를 사용하면 생성자 (ClassMirror)를 호출하고 필드 (FieldMirror)에 액세스하거나 메소드 (MethodMirror)를 호출 할 수 있습니다. 미러를 사용하여 반영되는 것에 대한 메타 데이터를 쿼리 할 수 ​​없습니다.

    // 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" 
    
    :

그래서 함께 예를 가하고 위의 설명을 반영, 이것이 당신이 필드를 검색 생성자를 호출하고 val을 읽을 것 어떻게, 정규화 된 클래스 이름을 가진 String을 부여