将 Scala Any 转换为 Java 对象

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/23892167/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 08:54:39  来源:igfitidea点击:

Convert Scala Any to Java Object

javascalareflectionscala-java-interop

提问by Torben

I've a problem using Java Reflection from Scala. My Code:

我在使用 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))

My problem is, that I need to pass a Map[String, Any], because one of the values is a Double, but newInstance needs Object, not Any.

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

I tried the same with scalas universe:

我对 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))

Problem here is, that I only introduced MyClass for the example. Later it should be a generic function like def create(values: Map[String, Any]): T. But then I got the following exception: "No TypeTag available for T"

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

Is there any way to transform these values?

有什么方法可以转换这些值吗?

Thank you

谢谢

采纳答案by Dan Getz

java.lang.Objectis equivalent to AnyRefin Scala, not Any. The idea is, Scala Double(roughly equivalent to Java double) is an Any, but not an AnyRef. java.lang.Doubleis an AnyRef, thus also an Any.

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

You can simply cast an Anyto AnyRef, which will perform the needed conversion to turn a Scala Doubleinto a java.lang.Double:

你可以简单地施放AnyAnyRef,这将执行所需的转换转斯卡拉Doublejava.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

回答by user3680494

Ok, I was a bit late but here goes:

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

The following works:

以下工作:

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

See also: Transforming Scala varargs into Java Object... varargs

另请参阅:将 Scala varargs 转换为 Java Object... varargs

Advice: I'd be very cautious using reflection. In Scala that is bad style. One way to limit/encapsulate it could be:

建议:我会非常谨慎地使用反射。在 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))