【发布时间】:2019-12-03 15:18:51
【问题描述】:
我正在编写一个函数来获取一些参数并提取它们的类型,但是只要这些参数在 Scala AnyVal (Int, Long, Double, ...) 下,它们就会转换为 Java 类型 (Integer, ...) .
这里是那个函数的一个小例子:
def functionX(args: Any*) = {
args.map(a => a.getClass)
}
val num: Int = 10
println(num1.getClass) // prints int
println(functionX(num1)) // prints Integer
我应该怎么做才能让所有参数类型(无论它们是 Int 还是 Integer)都保持原始类型并且不进行转换?
我还意识到,如果将变量放入 Scala 集合中,它也会被转换为 Java 类型:
val num: Int = 1
val numList = List(num)
println(num.getClass) // prints int
println(numList.head.getClass) // prints Integer
是否有任何 Java 自动装箱发生?但是,Scala 类型(如 Int)不是在 AnyVal 类下,也不是原始类型?
为了提供更多关于我为什么要这样做的背景信息,这里有一个例子:
trait MyTrait {
def myTraitMethod : String
}
object MyObj extends MyTrait {
def myTraitMethod = "Works fine"
def myObjMethod(num1: Int, num2: Int) = num1 * num2
}
case object Manager {
def currentObj: MyTrait = MyObj
}
val result = Manager.currentObj.myObjMethod
// I wanted to access this object method that is not in Trait, but
// it doesn't seem possible.
我没有做上面代码的最后一行,而是使用反射来做这样的事情:
def executeMethod(obj: MyTrait, methodName: String, args: Any*) = {
val argTypes = args.map(t => t.getClass)
val argsObjects = args.map(o => o.asInstanceOf[Object])
val method = obj.getClass.getMethod(methodName, argTypes:_*)
method.invoke(obj, argsObjects:_*)
}
val num = 10
val result = executeMethod(Manager.currentObj, "myObjMethod", num1, num2)
// That's where I have problem with Int being converted to Integer
// and the method is not found because it's (Int, Int) and not (Integer, Integer)
【问题讨论】:
-
编译时 Scala 类型和运行时 Java 类是不同的东西。在语言级别上,我们只有对象 (例如 Int),但运行时世界是另一回事,在 JVM 上运行时(记住 Scala 可能运行在其他平台,如 JS) 我们有对象和原语,但你不能要求原语的类,因此应用了自动装箱。你究竟为什么要这样做?
-
如果需要
AnyVal,为什么还要使用Any? -
Any通常是设计问题的症状 -
@HissashiRocha 如果这只是为了单元测试,那么对于这种情况有两种一般的想法。一个是你不应该测试私有行为的想法,因此你应该只测试公共 API (它会传递测试私有方法) - 另一方面,有一个论点是这样做正确的单元测试,你也应该测试这些方法,通常的解决方法是让它们
private[package],这样你的测试就可以在不需要反射的情况下访问它们。 -
@HissashiRocha 试试这个:
Manager.currentObj.asInstanceOf[MyObj.type].myObjMethod(2, 3)