Scala 为什么包对象中类型的类名包含;一揽子计划;运行时类名?

Scala 为什么包对象中类型的类名包含;一揽子计划;运行时类名?,scala,Scala,我试图生成在包对象中定义的类的运行时类名 例如: 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

我试图生成在
包对象中定义的类的运行时类名

例如:

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类型系统的一些东西…

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

Java的反射API对Scala一无所知,所以它们自然不能对您隐藏这种编码。调用
getClass.getCanonicalName
时,您将看到实际的类名,与编译代码时在
com/foo/bar/package\$MyCaseClass.class
中找到的类文件相对应

Scala的反射API确实知道Scala对包对象的编码,它们会对您隐藏合成的
package
类。这可以说是有道理的,因为编码的细节不在规范中(如果我没记错的话?),因此可能会因平台或语言版本等而异

这种差异有点令人困惑,但这并不是唯一一次您会遇到差异Scala reflection API隐藏了许多Java reflection无法隐藏的混乱等