为什么Scala在类名的末尾放一个美元符号?
在Scala中,当您查询对象的类或类名时,您将在打印输出的末尾得到一个错误的美元符号(“为什么Scala在类名的末尾放一个美元符号?,scala,reflection,classname,Scala,Reflection,Classname,在Scala中,当您查询对象的类或类名时,您将在打印输出的末尾得到一个错误的美元符号(“$”): object DollarExample { def main(args : Array[String]) : Unit = { printClass() } def printClass() { println(s"The class is ${getClass}") println(s"The class name is ${getClass.getName
$
”):
object DollarExample {
def main(args : Array[String]) : Unit = {
printClass()
}
def printClass() {
println(s"The class is ${getClass}")
println(s"The class name is ${getClass.getName}")
}
}
这导致:
The class is class com.me.myorg.example.DollarExample$
The class name is com.me.myorg.example.DollarExample$
当然,最后手动删除“$
”非常简单,但我想知道:
- 为什么会在那里?;及
- 是否有必要“配置Scala”来省略它
- 这是编译到JVM的结果。要在scala中创建
对象
,需要两个类。“基类”和生成singleton对象的类。因为这两个类不能具有相同的名称,所以会附加$
。您可能会修改编译器,使其不会生成一个$
,但您仍然需要一些方法来命名生成的类名。这里看到的是scalac将每个对象编译为两个JVM类。最后带有$的实际上是实现实际逻辑的真正的单例类,可能继承自其他类和/或trait。没有$的类是一个包含静态
转发器方法的类。我想这是为了Java互操作。另外,因为您实际上需要一种在scala中创建静态方法的方法,因为如果您想在JVM上运行程序,您需要一个publicstaticvoidmain(String[]args)
方法作为入口点
scala> :paste -raw
// Entering paste mode (ctrl-D to finish)
object Main { def main(args: Array[String]): Unit = ??? }
// Exiting paste mode, now interpreting.
scala> :javap -p -filter Main
Compiled from "<pastie>"
public final class Main {
public static void main(java.lang.String[]);
}
scala> :javap -p -filter Main$
Compiled from "<pastie>"
public final class Main$ {
public static Main$ MODULE$;
public static {};
public void main(java.lang.String[]);
private Main$();
}
scala>:粘贴-原始
//进入粘贴模式(按ctrl-D键完成)
对象Main{def Main(args:Array[String]):Unit=???}
//正在退出粘贴模式,现在正在解释。
scala>:javap-p-filter Main
从“”编译
公开期末班{
公共静态void main(java.lang.String[]);
}
scala>:javap-p-filter Main$
从“”编译
公开期末班主要课程${
公共静态主模块$;
公共静态{};
public void main(java.lang.String[]);
私人楼宇(元);;
}
我认为你对此无能为力。你的方法有几个问题:
- 您正在使用Java反射。Java反射对Scala一无所知
- 此外,您正在单例对象上使用Java反射,这是Java中甚至不存在的概念
- 最后,您使用Java反射请求单例对象的类,但在Scala中,单例对象不是类的实例
因此,换句话说:您要求错误语言的反射库对它不理解的内容进行反射,并返回甚至不存在的内容。难怪你会得到毫无意义的结果
如果改用Scala反射,结果会变得更加合理:
import scala.reflect.runtime.{universe => ru}
def getTypeTag[T: ru.TypeTag](obj: T) = ru.typeTag[T]
object Foo
val theType = getTypeTag(Foo).tpe
//=> theType: reflect.runtime.universe.Type = Foo.type
如您所见,Scala反射为Foo
返回正确的类型,即singleton类型(Java中不存在的另一种类型)Foo.type
一般来说,Java反射主要处理类,Scala反射处理类型
使用Scala反射而不是Java反射不仅更好,因为Java反射根本不理解Scala,而Scala反射理解Scala(事实上,Scala反射实际上只是调用编译器的不同接口,这意味着Scala反射知道编译器所做的一切),它还有一个额外的好处,即它可以在Scala的所有实现上工作,而您的代码会在Scala.js和Scala native上中断,这两个版本根本没有Java反射。尽管所有提到Java反射机制的答案都是正确的,但这仍然不能解决$sign或“.type”的问题在类名的末尾
您可以使用Scala classOf函数绕过反射问题
例如:
println(classOf[Int].getSimpleName)
println(classOf[Seq[Int]].getCanonicalName)
=> int
=> scala.collection.Seq
=> Seq
这样,您就得到了与示例Java中相同的结果想象一下如果scalac
将所有对象
编译为使用静态方法的类;一些基本的东西,如trait Me{def test()=println(“hello”)}
和object MeAgain extensed Me{override test()=println(“hello with Me”)}
——这是不可能的。