【问题标题】:Convert Scala Any to Java Object将 Scala Any 转换为 Java 对象
【发布时间】:2014-07-16 12:41:00
【问题描述】:

我在使用 Scala 的 Java 反射时遇到问题。我的代码:

case class MyClass(id: String, value: Double)     

def create(values: Map[String, Any]): MyClass = {
   val constructor = classOf[MyClass].getConstructors.head
   val arguments = classOf[MyClass].getDeclaredFields().map( f => values(f.getName) )
   constructor.newInstance(arguments: _*).asInstanceOf[MyClass]
} 

create(Map("id" -> "CE0D23A", "value" -> 828.32))

我的问题是,我需要传递一个 Map[String, Any],因为其中一个值是 Double,但 newInstance 需要 Object,而不是 Any。

我对 Scalas Universe 进行了同样的尝试:

case class MyClass(id: String, value: Double)     

def create(values: Map[String, Any]): MyClass = {
   val m = universe.runtimeMirror(getClass.getClassLoader)
   val myClass = universe.typeOf[MyClass].typeSymbol.asClass
   val cm = m.reflectClass(myClass)
   val ctro = universe.typeOf[MyClass].declaration(universe.nme.CONSTRUCTOR).asMethod
   val ctorm = cm.reflectConstructor(ctro)
   ctorm(values: _*).asInstanceOf[MyClass]
} 

create(Map("id" -> "CE0D23A", "value" -> 828.32))

这里的问题是,我只为示例介绍了 MyClass。稍后它应该是像def create(values: Map[String, Any]): T 这样的通用函数。但是后来我得到了以下异常:“T没有可用的TypeTag”

有没有办法转换这些值?

谢谢

【问题讨论】:

    标签: java scala reflection scala-java-interop


    【解决方案1】:

    java.lang.Object 等价于 Scala 中的AnyRef,而不是Any。这个想法是,Scala Double(大致相当于Java double)是Any,但不是AnyRefjava.lang.DoubleAnyRef,因此也是 Any

    您可以简单地将Any 转换为AnyRef,这将执行所需的转换以将Scala Double 转换为java.lang.Double

    scala> val x = 3.5
    x: Double = 3.5
    
    scala> x.getClass
    res0: Class[Double] = double
    
    scala> val y = x.asInstanceOf[AnyRef]
    y: AnyRef = 3.5
    
    scala> y.getClass
    res1: Class[_ <: AnyRef] = class java.lang.Double
    

    【讨论】:

    • 我添加了第二个基于 Scalas Universe 的示例。也许你也知道这个问题的解决方案?还是没有办法将 Scalas Universe 运行时反射与泛型一起使用?
    • 我不知道该怎么做,抱歉。也许您应该将其作为一个新的单独问题发布。
    【解决方案2】:

    好的,我有点晚了,但这里是:

    以下作品:

    constructor.newInstance(arguments.asInstanceOf[Array[AnyRef]]: _*).asInstanceOf[MyClass]
    

    另请参阅:Transforming Scala varargs into Java Object... varargs

    建议:我会非常谨慎地使用反射。在 Scala 中,这是一种糟糕的风格。限制/封装它的一种方法可能是:

    case class MyClass(id: String, value: Double)     
    
    object MyClass {
    
        import scala.util.Try
        def apply(map: Map[String, Any] /* this is asking for trouble */) : Option[MyClass]  =  for {
                id <- maybeT[String](map.get("id"))
                value <- maybeT[Double](map.get("value"))
            } yield MyClass(id, value)
    
        // a truly global utility?
        @inline def maybeT[T] ( a: Any /*Option[T]*/ ) : Option[T]= Try(a.asInstanceOf[Option[T]]).toOption.flatten //yep ugly as hell
    
    }
    
    
    MyClass(Map("id" -> "CE0D23A", "value" -> 828.32))
    

    【讨论】:

      猜你喜欢
      • 2015-08-24
      • 1970-01-01
      • 1970-01-01
      • 2014-04-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多