gpt4 book ai didi

java - 为什么将 Scala 伴随对象编译成两个类(Java 和 .NET 编译器)?

转载 作者:塔克拉玛干 更新时间:2023-11-03 03:36:03 24 4
gpt4 key购买 nike

object ScalaTrueRing {
def rule = println("To rule them all")
}

这段代码会被编译成java字节码,如果我反编译它,那么等效的Java代码是这样的:

public final class JavaTrueRing
{
public static final void rule()
{
ScalaTrueRing..MODULE$.rule();
}
}


/* */ public final class JavaTrueRing$
/* */ implements ScalaObject
/* */ {
/* */ public static final MODULE$;
/* */
/* */ static
/* */ {
/* */ new ();
/* */ }
/* */
/* */ public void rule()
/* */ {
/* 11 */ Predef..MODULE$.println("To rule them all");
/* */ }
/* */
/* */ private JavaTrueRing$()
/* */ {
/* 10 */ MODULE$ = this;
/* */ }
/* */ }

它被编译成两个类,如果我使用 Scala.net 编译器,它会被编译成 MSIL 代码,等效的 C# 代码是这样的:

public sealed class ScalaTrueRing
{
public static void rule()
{
ScalaTrueRing$.MODULE$.rule();
}
}

[Symtab]
public sealed class ScalaTrueRing$ : ScalaObject
{
public static ScalaTrueRing$ MODULE$;
public override void rule()
{
Predef$.MODULE$.println("To rule them all");
}
private ScalaTrueRing$()
{
ScalaTrueRing$.MODULE$ = this;
}
static ScalaTrueRing$()
{
new ScalaTrueRing$();
}
}

它也被编译成两个类。

为什么 Scala 编译器(一种用于 Java,一种用于 .NET)这样做?为什么不直接调用静态规则方法中的println方法呢?

最佳答案

重要的是要理解在 scala 中,对象 实际上是一等公民:它是一个可以像任何其他对象一样传递的实际实例。例如:

trait Greetings {
def hello() { println("hello") }
def bye() { println("bye") }
}

object FrenchGreetings extends Greetings {
override def hello() { println("bonjour") }
override def bye() { println("au revoir") }
}

def doSomething( greetings: Greetings ) {
greetings.hello()
println("... doing some work ...")
greetings.bye()
}

doSomething( FrenchGreetings )

与静态方法不同,我们的单例对象具有完整的多态行为。 doSomething 确实会调用我们覆盖的 hellobye 方法,而不是默认实现:

bonjour
... doing some work ...
au revoir

因此object 实现必须是一个合适的类。但是为了与java的互操作性,编译器还会生成静态方法,这些方法只转发到类的唯一实例 (MODULE$)(请参阅 JavaTrueRing.rule())。这样,java 程序就可以像访问普通静态方法一样访问单例对象的方法。现在您可能会问,为什么 scala 不将静态方法转发器与实例方法放在同一个类中。这会给我们类似的东西:

public final class JavaTrueRing implements ScalaObject {
public static final MODULE$;

static {
new JavaTrueRing();
}

public void rule() {
Predef.MODULE$.println("To rule them all");
}

private JavaTrueRing() {
MODULE$ = this;
}

// Forwarders
public static final void rule() {
MODULE$.rule();
}
}

我认为这不能这么简单的主要原因是因为在 JVM 中,您不能在同一个类中拥有具有相同签名的实例方法和静态方法。不过可能还有其他原因。

关于java - 为什么将 Scala 伴随对象编译成两个类(Java 和 .NET 编译器)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12783994/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com