Why does Scala place a dollar sign at the end of class names?

早过忘川 提交于 2019-11-30 02:49:28

问题


In Scala when you query an object for either its class or its class name, you'll get a rogue dollar sign ("$") at the tail end of the printout:

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}")
  }
}

This results with:

The class is class com.me.myorg.example.DollarExample$
The class name is com.me.myorg.example.DollarExample$

Sure, it's simple enough to manually remove the "$" at the end, but I'm wondering:

  • Why is it there?; and
  • Is there anyway to "configure Scala" to omit it?

回答1:


What you are seeing here is caused by the fact that scalac compiles every object to two JVM classes. The one with the $ at the end is actually the real singleton class implementing the actual logic, possibly inheriting from other classes and/or traits. The one without the $ is a class containing static forwarder methods. That's mosty for Java interop's sake I assume. And also because you actually need a way to create static methods in scala, because if you want to run a program on the JVM, you need a public static void main(String[] args) method as an entry point.

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$();
}

I don't think there's anything you can do about this.




回答2:


Although all answer that mention the Java reflection mechanism are correct this still doesnot solve the problem with the $ sign or the ".type" at the end of the class name.

You can bypass the problem of the reflection with the Scala classOf function.

Example:

println(classOf[Int].getSimpleName)
println(classOf[Seq[Int]].getCanonicalName)
=> int
=> scala.collection.Seq
=> Seq

With this you just have the same result as you have in for example Java




回答3:


There are several problems with your approach:

  • You are using Java Reflection. Java Reflection doesn't know anything about Scala.
  • Furthermore, you are using Java Reflection on a Singleton Object, a concept that doesn't even exist in Java.
  • Lastly, you are using Java Reflection to ask for the class of a Singleton Object, but in Scala, Singleton Objects aren't instances of a class.

So, in other words: you are asking the wrong language's reflection library to reflect on something it doesn't understand and return something that doesn't even exist. No wonder you are getting nonsense results!

If you use Scala Reflection instead, the results become a lot more sensible:

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

As you can see, Scala Reflection returns the correct type for Foo, namely the singleton type (another thing that doesn't exist in Java) Foo.type.

In general, whereas Java Reflection deals mainly in classes, Scala Reflection deals in Types.

Using Scala Reflection instead of Java Reflection is not only better because Java Reflection simply doesn't understand Scala whereas Scala Reflection does (in fact, Scala Reflection is actually just a different interface for calling into the compiler, which means that Scala Reflection knows everything the compiler does), it also has the added benefit that it works on all implementations of Scala, whereas your code would break on Scala.js and Scala-native, which simply don't have Java Reflection.




回答4:


This is a result of compiling to the JVM. To make an object in scala requires two classes. The "base" class and the class to make the singleton object. Because these classes can't both have the same name, the $ is appended. You could probably modify the compiler so that it won't make a $ but you will still need some way to name the generated class names.



来源:https://stackoverflow.com/questions/41570148/why-does-scala-place-a-dollar-sign-at-the-end-of-class-names

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!