将 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
Convert Scala Any to Java Object
提问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,但不是一个AnyRef。java.lang.Double是AnyRef,因此也是Any。
You can simply cast an Anyto AnyRef, which will perform the needed conversion to turn a Scala Doubleinto a java.lang.Double:
你可以简单地施放Any到AnyRef,这将执行所需的转换转斯卡拉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
回答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))

