为什么 Scala 在 class 名称的末尾放置一个美元符号?
Why does Scala place a dollar sign at the end of class names?
在 Scala 中,当您查询一个对象的 class 或 class 名称时,您会在末尾得到一个流氓美元符号 ("$
")打印输出:
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$
当然,手动删除末尾的“$
”很简单,但我想知道:
- 它为什么在那里?;和
- 有没有“configure Scala”来省略它?
这是编译到 JVM 的结果。要在 scala 中创建一个 object
需要两个 classes。 "base" class 和 class 来创建单例对象。因为这些 class 不能同名,所以附加了 $
。您可能会修改编译器,使其不会生成 $
,但您仍然需要一些方法来命名生成的 class 名称。
您在这里看到的是由于 scalac 将每个 object
编译为两个 JVM classes。末尾带有 $ 的实际上是实现实际逻辑的真正单例 class,可能继承自其他 classes and/or 特征。没有 $ 的是 class 包含 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$();
}
我认为您对此无能为力。
你的方法有几个问题:
- 您正在使用 Java 反射。 Java 反射对 Scala 一无所知。
- 此外,您正在对单例对象使用 Java 反射,这个概念在 Java.
中甚至不存在
- 最后,您正在使用 Java 反射来请求单例对象的 class,但在 Scala 中,单例对象不是 class 的实例。
因此,换句话说:您要求错误语言的反射库来反映它不理解的东西,return 甚至不存在的东西。难怪你会得到毫无意义的结果!
如果改用 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 反射 return 是 Foo
的正确类型,即单例类型(Java 中不存在的另一种类型)Foo.type
.
一般来说,Java 反射主要处理 classes,而 Scala 反射处理类型。
使用 Scala Reflection 而不是 Java Reflection 不仅更好,因为 Java Reflection 根本不理解 Scala 而 Scala Reflection 可以(事实上,Scala Reflection 实际上只是一个不同的接口调用编译器,这意味着 Scala 反射知道编译器所做的一切),它还有一个额外的好处,它适用于 Scala 的所有实现,而你的代码会在 Scala.js 和 Scala-native 上中断,这只是不要有Java反射。
虽然所有提到 Java 反射机制的答案都是正确的,但这仍然没有解决 $ 符号或 class 名称末尾的“.type”的问题。
你可以用Scala的classOf函数绕过反射的问题。
示例:
println(classOf[Int].getSimpleName)
println(classOf[Seq[Int]].getCanonicalName)
=> int
=> scala.collection.Seq
=> Seq
这样你就得到了和你在 Java
中得到的结果一样的结果
在 Scala 中,当您查询一个对象的 class 或 class 名称时,您会在末尾得到一个流氓美元符号 ("$
")打印输出:
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$
当然,手动删除末尾的“$
”很简单,但我想知道:
- 它为什么在那里?;和
- 有没有“configure Scala”来省略它?
这是编译到 JVM 的结果。要在 scala 中创建一个 object
需要两个 classes。 "base" class 和 class 来创建单例对象。因为这些 class 不能同名,所以附加了 $
。您可能会修改编译器,使其不会生成 $
,但您仍然需要一些方法来命名生成的 class 名称。
您在这里看到的是由于 scalac 将每个 object
编译为两个 JVM classes。末尾带有 $ 的实际上是实现实际逻辑的真正单例 class,可能继承自其他 classes and/or 特征。没有 $ 的是 class 包含 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$();
}
我认为您对此无能为力。
你的方法有几个问题:
- 您正在使用 Java 反射。 Java 反射对 Scala 一无所知。
- 此外,您正在对单例对象使用 Java 反射,这个概念在 Java. 中甚至不存在
- 最后,您正在使用 Java 反射来请求单例对象的 class,但在 Scala 中,单例对象不是 class 的实例。
因此,换句话说:您要求错误语言的反射库来反映它不理解的东西,return 甚至不存在的东西。难怪你会得到毫无意义的结果!
如果改用 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 反射 return 是 Foo
的正确类型,即单例类型(Java 中不存在的另一种类型)Foo.type
.
一般来说,Java 反射主要处理 classes,而 Scala 反射处理类型。
使用 Scala Reflection 而不是 Java Reflection 不仅更好,因为 Java Reflection 根本不理解 Scala 而 Scala Reflection 可以(事实上,Scala Reflection 实际上只是一个不同的接口调用编译器,这意味着 Scala 反射知道编译器所做的一切),它还有一个额外的好处,它适用于 Scala 的所有实现,而你的代码会在 Scala.js 和 Scala-native 上中断,这只是不要有Java反射。
虽然所有提到 Java 反射机制的答案都是正确的,但这仍然没有解决 $ 符号或 class 名称末尾的“.type”的问题。
你可以用Scala的classOf函数绕过反射的问题。
示例:
println(classOf[Int].getSimpleName)
println(classOf[Seq[Int]].getCanonicalName)
=> int
=> scala.collection.Seq
=> Seq
这样你就得到了和你在 Java
中得到的结果一样的结果