为什么Scala在类名末尾放置一个美元符号?

sme*_*eeb 10 reflection scala 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}")
  }
}
Run Code Online (Sandbox Code Playgroud)

结果如下:

The class is class com.me.myorg.example.DollarExample$
The class name is com.me.myorg.example.DollarExample$
Run Code Online (Sandbox Code Playgroud)

当然,最后手动删除" $" 很简单,但我想知道:

  • 为什么会这样?和
  • 无论如何" 配置Scala "省略它?

Jas*_*r-M 16

你在这里看到的是scalac编译每object两个JVM类的事实.最后$的那个实际上是实现实际逻辑的真正的单例类,可能继承自其他类和/或特征.没有$的那个是包含static转发器方法的类.我认为这对于Java互操作来说很清楚.还因为你实际上需要一种在scala中创建静态方法的方法,因为如果你想在JVM上运行程序,你需要一个public static void main(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$();
}
Run Code Online (Sandbox Code Playgroud)

我认为你无能为力.


小智 9

虽然提到Java反射机制的所有答案都是正确的,但这仍然无法解决类名末尾的$符号或".type"的问题.

您可以使用Scala classOf函数绕过反射问题.

例:

println(classOf[Int].getSimpleName)
println(classOf[Seq[Int]].getCanonicalName)
=> int
=> scala.collection.Seq
=> Seq
Run Code Online (Sandbox Code Playgroud)

通过这种方式,您可以获得与Java相同的结果


Jör*_*tag 6

你的方法有几个问题:

  • 您正在使用 Java 反射。Java Reflection 对 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
Run Code Online (Sandbox Code Playgroud)

如您所见,Scala 反射为 返回正确的类型Foo,即单例类型(Java 中不存在的另一种类型)Foo.type

一般来说,Java 反射主要处理类,而 Scala 反射主要处理类型。

使用 Scala Reflection 而不是 Java Reflection 不仅更好,因为 Java Reflection 根本不理解 Scala 而 Scala Reflection 可以(实际上,Scala Reflection 实际上只是调用编译器的不同接口,这意味着 Scala Reflection 知道一切编译器),它也有它适用于斯卡拉的所有实现,而你的代码将在Scala.js和Scala本地的,它只是不破的额外好处Java反射。