将 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.Object
is equivalent to AnyRef
in Scala, not Any
. The idea is, Scala Double
(roughly equivalent to Java double
) is an Any
, but not an AnyRef
. java.lang.Double
is 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 Any
to AnyRef
, which will perform the needed conversion to turn a Scala Double
into 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))