복붙노트

[SCALA] 스칼라 : 어떻게 동적 객체와 반사를 사용하여 메서드 Invoke를 인스턴스화합니까?

SCALA

스칼라 : 어떻게 동적 객체와 반사를 사용하여 메서드 Invoke를 인스턴스화합니까?

동적 객체와 반사를 사용하여 메서드 Invoke를 인스턴스화에 스칼라에서, 가장 좋은 방법은 무엇입니까?

나는 다음과 같은 자바 코드의 스칼라 환산을하고 싶습니다 :

Class class = Class.forName("Foo");
Object foo = class.newInstance();
Method method = class.getMethod("hello", null);
method.invoke(foo, null);

위의 코드에서 클래스 이름과 메소드 이름을 모두 동적으로 전달됩니다. 자바 위의 메커니즘은 아마 푸 안녕하세요 ()에 사용될 수 있지만, 스칼라 유형은 한 -에 - 하나와 일치하지 않는 자바의 그것과. 예를 들어, 클래스는 단일 개체에 대해 암시 적으로 선언 할 수있다. 또한 스칼라 방법은 기호를 모든 종류의 이름이 될 수 있습니다. 둘 다 이름 맹 글링에 의해 해결된다. 자바와 스칼라 사이에 상호 운용성을 참조하십시오.

천국과 지옥 - 또 다른 문제는 스칼라에서 반사에 설명 된 해결 과부하 및 오토 박싱에 의해 매개 변수의 매칭 될 것으로 보인다.

해결법

  1. ==============================

    1.사용 구조 타이핑 : 자바 반사 메소드를 호출에 의지하지 않고 반사적으로 메소드를 호출 할 수있는 쉬운 방법이있다.

    사용 구조 타이핑 : 자바 반사 메소드를 호출에 의지하지 않고 반사적으로 메소드를 호출 할 수있는 쉬운 방법이있다.

    필요없는 반사 (물론, 스칼라는 반사 아래를하고있다하지만 우리는 그것을 할 필요가 없습니다) : 그냥 필요한 메소드 서명은 다음 메소드를 호출있는 구조 유형의 객체 참조를 캐스팅.

    class Foo {
      def hello(name: String): String = "Hello there, %s".format(name)
    }
    
    object FooMain {
    
      def main(args: Array[String]) {
        val foo  = Class.forName("Foo").newInstance.asInstanceOf[{ def hello(name: String): String }]
        println(foo.hello("Walter")) // prints "Hello there, Walter"
      }
    }
    
  2. ==============================

    2.난 그냥 하나 개의 스칼라 2.8 실험의 기능을 보완하는 것, 그래서 VonC 월터 장에 의한 대답은 아주 좋다. 사실, 난 그냥 scaladoc을 복사 할 수 있습니다, 그것을 옷을 귀찮게하지 않습니다.

    난 그냥 하나 개의 스칼라 2.8 실험의 기능을 보완하는 것, 그래서 VonC 월터 장에 의한 대답은 아주 좋다. 사실, 난 그냥 scaladoc을 복사 할 수 있습니다, 그것을 옷을 귀찮게하지 않습니다.

    object Invocation
      extends AnyRef
    
    class Obj { private def foo(x: Int, y: String): Long = x + y.length }
    
    import scala.reflect.Invocation._
    (new Obj) o 'foo(5, "abc")                 // the 'o' method returns Any
    val x: Long = (new Obj) oo 'foo(5, "abc")  // the 'oo' method casts to expected type.
    
  3. ==============================

    3.경우 당신은 스칼라 2.10 객체 (클래스가 아닌)의 메소드를 호출 할 필요가 당신은 당신이 이런 식으로 작업을 수행 할 수 있습니다, 문자열 등의 방법 및 개체의 이름을 가지고 :

    경우 당신은 스칼라 2.10 객체 (클래스가 아닌)의 메소드를 호출 할 필요가 당신은 당신이 이런 식으로 작업을 수행 할 수 있습니다, 문자열 등의 방법 및 개체의 이름을 가지고 :

    package com.example.mytest
    
    import scala.reflect.runtime.universe
    
    class MyTest
    
    object MyTest {
    
      def target(i: Int) = println(i)
    
      def invoker(objectName: String, methodName: String, arg: Any) = {
        val runtimeMirror = universe.runtimeMirror(getClass.getClassLoader)
        val moduleSymbol = runtimeMirror.moduleSymbol(
          Class.forName(objectName))
    
        val targetMethod = moduleSymbol.typeSignature
          .members
          .filter(x => x.isMethod && x.name.toString == methodName)
          .head
          .asMethod
    
        runtimeMirror.reflect(runtimeMirror.reflectModule(moduleSymbol).instance)
          .reflectMethod(targetMethod)(arg)
      }
    
      def main(args: Array[String]): Unit = {
        invoker("com.example.mytest.MyTest$", "target", 5)
      }
    }
    

    이 표준 출력에 5를 인쇄합니다. 스칼라 문서에서 더 자세한 사항.

  4. ==============================

    4.instanciation 부분은 매니페스트를 사용할 수 있습니다이 SO의 대답을 참조

    instanciation 부분은 매니페스트를 사용할 수 있습니다이 SO의 대답을 참조

     class Test[T](implicit m : Manifest[T]) {
       val testVal = m.erasure.newInstance().asInstanceOf[T]
     }
    
    class Foo
    val t = new Test[Foo]
    
    scala> new Test[Set[String]] 
    java.lang.InstantiationException: scala.collection.immutable.Set
    at java.lang.Class.newInstance0(Class.java:340)
    

    진정한 타입 그래서 안전 솔루션은 공장을 사용하는 것입니다.

    참고 :이 스레드에 명시된 바와 같이 매니페스트 여기에 숙박을하지만. "만 사용이 클래스 인스턴스와 같은 유형의 삭제에 대한 액세스를 제공하는 것입니다"지금이다

    그런 다음 반사를 통해 방법을 얻을 수 있습니다 :

    classOf[ClassName].getMethod("main", classOf[Array[String]]) 
    

    그것을 호출

    scala> class A {
         | def foo_=(foo: Boolean) = "bar"
         | }
    defined class A
    
    scala>val a = new A
    a: A = A@1f854bd
    
    scala>a.getClass.getMethod(decode("foo_="),
    classOf[Boolean]).invoke(a, java.lang.Boolean.TRUE)
    res15: java.lang.Object = bar 
    
  5. ==============================

    5.@ 네딤의 대답에서 최대 근무, 여기, 전체 응답의 기초 우리가 순진 클래스의 인스턴스를 아래의 주요 차이점은 여기에있는. 이 코드는 여러 생성자의 경우를 처리하고 더 전체 답을 의미하는 것입니다하지 않습니다.

    @ 네딤의 대답에서 최대 근무, 여기, 전체 응답의 기초 우리가 순진 클래스의 인스턴스를 아래의 주요 차이점은 여기에있는. 이 코드는 여러 생성자의 경우를 처리하고 더 전체 답을 의미하는 것입니다하지 않습니다.

    import scala.reflect.runtime.universe
    
    case class Case(foo: Int) {
      println("Case Case Instantiated")
    }
    
    class Class {
      println("Class Instantiated")
    }
    
    object Inst {
    
      def apply(className: String, arg: Any) = {
        val runtimeMirror: universe.Mirror = universe.runtimeMirror(getClass.getClassLoader)
    
        val classSymbol: universe.ClassSymbol = runtimeMirror.classSymbol(Class.forName(className))
    
        val classMirror: universe.ClassMirror = runtimeMirror.reflectClass(classSymbol)
    
        if (classSymbol.companion.toString() == "<none>") // TODO: use nicer method "hiding" in the api?
        {
          println(s"Info: $className has no companion object")
          val constructors = classSymbol.typeSignature.members.filter(_.isConstructor).toList
          if (constructors.length > 1) { 
            println(s"Info: $className has several constructors")
          } 
          else {
            val constructorMirror = classMirror.reflectConstructor(constructors.head.asMethod) // we can reuse it
            constructorMirror()
          }
    
        }
        else
        {
          val companionSymbol = classSymbol.companion
          println(s"Info: $className has companion object $companionSymbol")
          // TBD
        }
    
      }
    }
    
    object app extends App {
      val c = Inst("Class", "")
      val cc = Inst("Case", "")
    }
    

    여기에 컴파일 것 build.sbt입니다 :

    lazy val reflection = (project in file("."))
      .settings(
        scalaVersion := "2.11.7",
        libraryDependencies ++= Seq(
          "org.scala-lang" % "scala-compiler" % scalaVersion.value % "provided",
          "org.scala-lang" % "scala-library" % scalaVersion.value % "provided"
        )
      )
    
  6. from https://stackoverflow.com/questions/1469958/scala-how-do-i-dynamically-instantiate-an-object-and-invoke-a-method-using-refl by cc-by-sa and MIT license