2016-10-06 2 views
4

Wenn wir ein Final in Java erstellen, ist garantiert, dass es auch zur Laufzeit nicht geändert werden kann, weil die JVM dies garantiert.Scala - Wie wird Val-Immutability zur Laufzeit garantiert

Java-Klasse:

public class JustATest { 
    public final int x = 10; 
} 

javap dekompilierten:

Zusammengestellt von "JustATest.java"

public class JustATest { 
    public final int x; 

    public JustATest(); 
    Code: 
     0: aload_0 
     1: invokespecial #1    // Method java/lang/Object."<init>":()V 
     4: aload_0 
     5: bipush  10 
     7: putfield  #2     // Field x:I 
     10: return 
} 

Aber in scala, erklären, wenn wir eine val, es kompiliert in eine normale ganze Zahl und es gibt keinen Unterschied zwischen var und val in t Erms der Dekompilierung ausgegeben.

Original-Scala Klasse:

class AnTest { 

    val x = 1 
    var y = 2 
} 

dekompilierten Ausgang:

Compiled from "AnTest.scala" 
public class AnTest { 
    public int x(); 
    Code: 
     0: aload_0 
     1: getfield  #14     // Field x:I 
     4: ireturn 

    public int y(); 
    Code: 
     0: aload_0 
     1: getfield  #18     // Field y:I 
     4: ireturn 

    public void y_$eq(int); 
    Code: 
     0: aload_0 
     1: iload_1 
     2: putfield  #18     // Field y:I 
     5: return 

    public AnTest(); 
    Code: 
     0: aload_0 
     1: invokespecial #25     // Method java/lang/Object."<init>":()V 
     4: aload_0 
     5: iconst_1 
     6: putfield  #14     // Field x:I 
     9: aload_0 
     10: iconst_2 
     11: putfield  #18     // Field y:I 
     14: return 
} 

Mit diesen Informationen das Konzept der Unveränderlichkeit eines val wird nur bei der Kompilierung durch den scala Compiler gesteuert ? Wie ist dies zur Laufzeit garantiert?

+0

Wie Sie sagten, ist die Val-Unveränderlichkeit nur zur Kompilierzeit garantiert. Und Sie können tatsächlich ein val mithilfe der Laufzeitreflexion mutieren. –

+0

Die einzige Möglichkeit, einen Laufzeitwert zu ändern, besteht darin, dass Sie Reflektionen in Ihrem Code vornehmen. Welche Art von "Laufzeitgarantien" suchen Sie? –

+0

@YuvalItzchakov: Das Konzept einer Wert-Unveränderlichkeit ist in Java nicht vorhanden, d. H. Ein Int kann sich ändern, aber im Falle von Scala garantiert ein Wert, dass es nicht geändert werden kann. In diesem Fall, wie wird dies mit dem jvm kommuniziert, da sich ein val nicht wie ein endgültiges –

Antwort

11

In Scala, Förderungsimmutabilität über val ist eine Kompilierzeit Erzwingung, die nichts mit dem emittierten Bytecode zu tun hat. In Java geben Sie an, dass, wenn das Feld final ist, damit es nicht neu zugewiesen wird. In Scala bedeutet die Deklaration einer Variablen mit val nur, dass sie nicht neu zugewiesen werden kann, aber überschrieben werden kann. Wenn Sie ein Feld final sein wollen, müssen Sie es spezifizieren, wie Sie in Java tun:

class AnTest { 
    final val x = 10 
} 

Welche ergibt:

public class testing.ReadingFile$AnTest$1 { 
    private final int x; 

    public final int x(); 
    Code: 
     0: bipush  10 
     2: ireturn 

    public testing.ReadingFile$AnTest$1(); 
    Code: 
     0: aload_0 
     1: invokespecial #19     // Method java/lang/Object."<init>":()V 
     4: return 
} 

die mit dem Byte-Code entspricht Sie sehen in Java , außer der Compiler hat einen Getter für x ausgegeben.

1

Die wirklich einfache Antwort ist: Es gibt einige Scala Features, die in JVM Bytecode codiert werden können, und einige, die nicht können.

Insbesondere gibt es einige Constraints, die nicht in JVM-Bytecode, z.B. sealed oder private[this] oder val. Das heißt, wenn Sie den kompilierten JVM-Bytecode einer Scala-Quelldatei in die Hände bekommen, können Sie Dinge tun, die Sie nicht mit Scala tun können, indem Sie über eine Sprache, die nicht Scala ist, mit dem Code interagieren.

Dies ist nicht spezifisch für das JVM-Backend, Sie haben ähnliche und noch ausgeprägtere Probleme mit Scala.js, da das Kompilierungsziel (ECMAScript) noch weniger Möglichkeiten bietet, Einschränkungen auszudrücken als JVM-Bytecode.

Aber wirklich, das ist nur ein allgemeines Problem: Ich kann eine Sprache so sicher und rein wie Haskell, kompilieren Sie es in nativen Code, und wenn ich die kompilierte binäre in die Hände bekomme, wird die Sicherheit verloren gehen.Tatsächlich führen die meisten Haskell-Compiler eine (fast) vollständige Typlöschung durch, so dass buchstäblich keine Typen und keine Typbeschränkungen nach der Kompilierung übrig sind.

Verwandte Themen