java.lang.NoSuchMethodException:scala.collection.immutable。$ colon $ colon

时间:2018-10-29 11:27:58

标签: java scala intellij-idea sbt scala-reflect

我正在尝试使用变量作为String类型的动态调用函数,即变量将包含一个函数名称为String。因此,我需要使用该变量来调用函数。

因此,我正在使用Scala反射。如果函数接受数据类型为Sting,则可以正常工作,但会引发错误List [Map [String,Double]]

我在下面的链接中引用了代码

Is there any Scala feature that allows you to call a method whose name is stored in a string?

和下面是我要测试的测试程序

package test

import scala.collection.immutable.Map

class DynamicaVariable {
 def cat(s1: List[Map[String, Double]]) = {
  println(s1)
 }
}

object DynamicaVariable{
 def main(args: Array[String]): Unit = {

 val obj = new DynamicaVariable
 val data = List(
  Map("a" -> 1.0, "b" -> 267.0, "c" -> 26.0, "d" -> 2.0), Map("a" -> 1.0, "b" -> 2678.0, "c" -> 40.0, "d" -> 2.0), Map("a" -> 4.0, "b" -> 267.0, "c" -> 26.0, "d" -> 2.0), Map("a" -> 1.0, "b" -> 2678.0, "c" -> 90.0, "d" -> 17.0)
)
 val functionName = "cat"
 val method = obj.getClass.getMethod(functionName,data.getClass)
 method.invoke(obj,data)
}
}

我的scala版本是2.11.6,我正在使用IntelliJ。我也检查了SDK版本。并取消选中scala下的“在编译过程中运行工作表”

但是仍然没有运气!任何想法都会有所帮助。谢谢!

2 个答案:

答案 0 :(得分:1)

如此处Runtime Classes in Java vs. Runtime Types in Scala

所述
  

在Scala类上使用Java反射可能会返回令人惊讶或错误的结果

在您的情况下,由于 data 的类型为 scala.collection.immutable.List ,因此您需要使用Scala反射来获取 data val在运行时。这是一个例子

import scala.reflect.ClassTag
import scala.reflect.classTag

class DynamicaVariable {
    def cat(s1: List[Map[String, Double]]) = {
        println(s1)
    }
}

object DynamicaVariable{
    def main(args: Array[String]): Unit = {
        val obj = new DynamicaVariable
        val data = List(Map("a" -> 1.0, "b" -> 267.0, "c" -> 26.0, "d" -> 2.0)
                        , Map("a" -> 1.0, "b" -> 2678.0, "c" -> 40.0, "d" -> 2.0)
                        , Map("a" -> 4.0, "b" -> 267.0, "c" -> 26.0, "d" -> 2.0)
                        , Map("a" -> 1.0, "b" -> 2678.0, "c" -> 90.0, "d" -> 17.0))
        val functionName = "cat"
        val method = obj.getClass.getMethod(functionName, getClassOf(data).runtimeClass)

        method.invoke(obj,data)
    }

    def getClassOf[T: ClassTag](obj: T) = classTag[T]
}

答案 1 :(得分:0)

我在下面提供了一个可行的解决方案,该解决方案使用了 scala反射与@ValentinCarnu的java / scala混合。

我不是反思大师,所以我不知道以下内容是否惯用。

import scala.collection.immutable.Map
import scala.reflect.runtime.{universe => ru}

class DynamicaVariable {
  def cat(s1: List[Map[String, Double]]) = {
    println(s1)
  }
}

object DynamicaVariable {
  def main(args: Array[String]): Unit = {

    val obj = new DynamicaVariable
    val data = List(
      Map("a" -> 1.0, "b" -> 267.0, "c" -> 26.0, "d" -> 2.0),
      Map("a" -> 1.0, "b" -> 2678.0, "c" -> 40.0, "d" -> 2.0),
      Map("a" -> 4.0, "b" -> 267.0, "c" -> 26.0, "d" -> 2.0),
      Map("a" -> 1.0, "b" -> 2678.0, "c" -> 90.0, "d" -> 17.0)
    )
    val functionName = "cat"
    val mirror = ru.runtimeMirror(getClass.getClassLoader)
    val instanceMirror: ru.InstanceMirror = mirror.reflect(obj)
    val classSymbol = mirror.classSymbol(obj.getClass)
    val termName: ru.MethodSymbol = classSymbol.info.decl(ru.TermName(functionName)).asMethod


    val methodMirror: ru.MethodMirror = instanceMirror.reflectMethod(termName)
    methodMirror.apply(data)
  }
}