为什么包对象中类型的类名称在运行时类名称中包含“包”?

时间:2019-04-23 17:47:46

标签: scala

我正在尝试生成package object中定义的类的运行时类名称。

示例:

package com.foo

package object bar {
  case class MyCaseClass()

}

import bar._
MyCaseClass().getClass.getCanonicalName

以上内容将生成com.foo.bar.package.MyCaseClass

如果我使用WeakTypeTag,它将正确生成类型为com.foo.bar.MyCaseClass

package com.foo

trait MyTrait
case class MyImpl extends MyTrait

def getType[T](t: T)(implicit weakTypeTag WeakTypeTag[T]): String = {
   weakTypeTag.tpe.fullName
}

上述行为差异的原因是什么?我知道我一定缺少有关Scala类型系统的东西...

1 个答案:

答案 0 :(得分:3)

这与类型系统无关,而与JVM上包对象的编码无关。例如,JVM没有包级方法,因此Scala编译器必须创建一个综合类,该类具有与包对象中的定义相对应的静态方法,内部类等。该类的名称为package,是一个任意但不言自明的名称,它的优点是在Scala和Java中都是关键字,因此不太可能导致与非合成代码的冲突。

Java的反射API对Scala一无所知,因此自然无法向您隐藏此编码。调用getClass.getCanonicalName时,您会看到实际的类名称,该名称与编译代码时在com/foo/bar/package\$MyCaseClass.class上找到的类文件相对应。

Scala的反射API确实了解Scala的封装对象编码,它们将向您隐藏合成的package类。可以说这是有道理的,因为编码的细节不在规范中(如果我没记错的话?),并且在平台或语言版本等方面可能有所不同。

差异有点令人困惑,但这不是您唯一遇到分歧的地方-Scala反射API隐藏了Java反射无法做到的许多改头换面等。