Why does Scala place a dollar sign at the end of c

2020-03-01 09:15发布

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?

4条回答
Animai°情兽
2楼-- · 2020-03-01 09:25

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.

查看更多
Fickle 薄情
3楼-- · 2020-03-01 09:26

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

查看更多
时光不老,我们不散
4楼-- · 2020-03-01 09:27

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.

查看更多
Summer. ? 凉城
5楼-- · 2020-03-01 09:36

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.

查看更多
登录 后发表回答