2012-10-08 10 views
6
object ScalaTrueRing { 
    def rule = println("To rule them all") 
} 

dieses Stück Code in Java-Bytecode kompiliert werden, wenn ich es zu dekompilieren, dann das Äquivalent von Java-Code zu diesem ähnlich ist:Warum wird ein Begleitobjekt von Scala in zwei Klassen kompiliert (Java- und .NET-Compiler)?

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; 
/* */ } 
/* */ } 

es in zwei Klassen kompiliert, und wenn ich Scala verwenden .net-Compiler, wird es in MSIL Code kompiliert werden, und der äquivalente C# -Code ist wie folgt:

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

es wird auch in zwei Klassen zusammengestellt.

Warum machen Scala Compiler (der für Java und der für .NET) das? Warum ruft es die println-Methode nicht nur in der statischen Regelmethode auf?

+0

Woher kommt also die Klasse 'JavaTrueRing $'? –

+0

@Der Elite Gentleman, es ist echter Name ist ScalaTrueRing $, ich änderte den Namen, um explizit zu zeigen, dass es Java-Code ist. Ich habe die Klassendatei dekompiliert und verstanden. – CuiPengFei

Antwort

8

Es ist wichtig zu verstehen, dass in Scala, object ist eigentlich ein First-Class-Bürger: Es ist eine tatsächliche Instanz, die als irgendein anderes Objekt weitergegeben werden kann. Am Beispiel:

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) 

Im Gegensatz zu statischen Methoden hat unser Singleton-Objekt vollständig polymorphe beheviour. doSomething wird in der Tat unsere außer Kraft gesetzt hello und bye Methoden aufrufen, und nicht die Standardimplementierungen:

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

So ist die object Implementierung muss unbedingt eine richtige Klasse sein. Aber für die Interoperabilität mit Java, generiert der Compiler auch statische Methoden, die nur an die eindeutige Instanz (MODULE$) der Klasse weiterleiten (siehe JavaTrueRing.rule()). Auf diese Weise kann ein Java-Programm auf die Methoden des Singleton-Objekts als normale statische Methode zugreifen. Nun könnten Sie sich fragen, warum scala die statischen Methodenübermittler nicht in derselben Klasse wie die Instanzmethoden platziert. Dies würde uns so etwas wie:

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

Ich glaube, dass der Hauptgrund, warum dies nicht so einfach sein kann, ist, weil in der JVM Sie nicht in der gleichen Klasse eine Instanzmethode und eine statische Methode wth derselben haben kann Unterschrift. Es kann jedoch andere Gründe geben.

1

Diese Blog entry "A Look at How Scala Compiles to Java" sollte Ihre Frage beantworten

Typischerweise Classname $ .class- Ergebnisse der inneren Klassen sind - Scala offensichtlich etwas anders.

+1

In diesem Blogpost wird erklärt, was der Scala-Compiler tut, aber das erklärt nicht, warum. Warum ruft der Scala-Compiler nicht einfach die Methode println in der statischen Regelmethode auf? – CuiPengFei

3

Paraphrasieren von "Programmieren in Scala" - Weil ein Scala-Companion-Objekt (Singleton-Objekt) mehr ist als nur ein Halter für statische Methoden. Da es sich um eine Instanz einer anderen Java-Klasse handelt, kann der Entwickler Singleton-Objekte und Mix-In-Merkmale erweitern. Dies ist mit statischen Methoden nicht möglich.

Verwandte Themen