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

tego kawałka kodu zostaną skompilowane do kodu Java bajt, jeśli dekompilować go, a następnie odpowiednikiem kodu Java jest podobny do tego:Dlaczego obiekt towarzyszący Scala jest kompilowany w dwie klasy (zarówno kompilatory Java, jak i .NET)?

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

to skompilowane na dwie klasy, a jeśli mogę użyć Scala .net kompilator, to będzie kompilowany do kodu MSIL, a odpowiednikiem kodu C# jest tak:

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

jest również skompilowana na dwie klasy.

Dlaczego kompilatory Scala (ten dla Java i jeden dla .NET) to zrobić? Dlaczego po prostu nie wywołuje metody println w metodzie reguły statycznej?

+0

Skąd pochodzi klasa 'JavaTrueRing $'? –

+0

@The Elite Gentleman to prawdziwe imię ScalaTrueRing $, zmieniłem nazwę, aby wyraźnie pokazać, że jest to kod Java. Dekompilowałem plik klasy i dostałem to. – CuiPengFei

Odpowiedz

8

Ważne jest, aby zrozumieć, że w scala, object w rzeczywistości jest obywatelem pierwszej klasy: jest to faktyczna instancja, którą można przekazać jak każdy inny obiekt. Poprzez przykład:

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) 

W przeciwieństwie do metod statycznych, nasz obiekt posiada pełny Singleton polimorficzny beheviour. doSomething rzeczywiście nazwać nasze nadpisane hello i bye metod i nie implementacje domyślne:

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

więc realizacja object musi koniecznie być właściwa klasa. Ale dla współdziałania z java, kompilator generuje również statyczne metody, które po prostu przekazują do unikalnej instancji (MODULE$) tej klasy (zobacz JavaTrueRing.rule()). W ten sposób program java może uzyskać dostęp do metod obiektu singleton jako normalnej metody statycznej. Teraz możesz zapytać, dlaczego scala nie umieszcza forwarderów metod statycznych w tej samej klasie, co metody instancji. Dałoby to nam coś takiego:

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

wierzę, że głównym powodem, dlaczego to nie może być tak proste, ponieważ w JVM nie można mieć w tej samej klasie metodę instancji i metody statyczne wth samo podpis. Może być jednak z innych powodów.

1

Ten Blog entry "A Look at How Scala Compiles to Java" należy odpowiedzieć na pytanie

Zazwyczaj ClassName $ .class są wyniki klas wewnętrznych - Scala jest oczywiście nieco inna.

+1

ten post na blogu wyjaśnia, co robi kompilator Scala, ale nie wyjaśnia dlaczego. Dlaczego kompilator Scala nie wywołuje metody println w metodzie reguły statycznej? – CuiPengFei

3

Parafrazowanie z "Programowanie w Scali" - Ponieważ obiekt towarzyszący scala (obiekt singletonowy) jest czymś więcej niż tylko uchwytem metod statycznych. Będąc instancją innej klasy Java, pozwala programistom rozszerzać obiekty singleton i mieszać cechy. Nie można tego zrobić za pomocą metod statycznych.

Powiązane problemy