Antwort

4

Wenn Sie Bedenken hinsichtlich des Speicherbedarfs haben, sollten Sie dieses Feld in das Begleitobjekt verschieben.

Ja, jede Instanz der Klasse Foo hat den Wert pi - der Scala-Compiler wird diese Deklaration nicht eliminieren. Mit der JVM-Reflektion können Sie letzte Modifikatoren für Klassenelemente entfernen, und das Unsafe-Objekt ermöglicht sogar das Modifizieren dieser Elemente. Also - der Scala-Compiler könnte Code mit überraschenden Ergebnissen erzeugen, indem er dieses Feld entfernt, so dass diese Optimierung nicht angewendet wird.

... 
    minor version: 0 
    major version: 50 
    flags: ACC_PUBLIC, ACC_SUPER 
... 
{ 
    private final int pi; 
    flags: ACC_PRIVATE, ACC_FINAL 


    public final int pi(); 
    flags: ACC_PUBLIC, ACC_FINAL 
    LineNumberTable: 
     line 243: 0 
    LocalVariableTable: 
     Start Length Slot Name Signature 
... 

In der Tat, einige Compiler-Transformationen (z Spezialisierung) könnten sogar endgültige Modifikatoren auf Mitglieder unter der Motorhaube entfernen, so etwas, das final in Scala Code fühlt sich vielleicht nicht final auf der Bytecode-Ebene sein.

Dieser:

class Foo[@specialized T] { 
    final val pi: T = null.asInstanceOf[T] 
} 

wird:

... 
    public final T pi; 
    flags: ACC_PUBLIC, ACC_FINAL 
    Signature: #9       // TT; 


    public T pi(); 
    flags: ACC_PUBLIC 
    LineNumberTable: 
     line 243: 0 
    ... 

Oben die pi Accessormethode (d.h. seine Getter) nicht mehr endgültig.

Und weder das JIT in der Oracle JVM entfernt dieses Mitglied aus der Objektdarstellung im Speicher zur Laufzeit - die Laufzeitgröße des Foo Objekts auf einer 32-Bit-JVM wird 16 Bytes (8 Bytes Objektkopf + 4 Bytes für ein ganzzahliges Feld, auf eine 8-Byte-Grenze gerundet). Die JIT kann jedoch entscheiden, den konstanten Wert aus dem letzten Feld in Teile des Codes einzubinden, so dass einige Feldschreibvorgänge eliminiert werden.

3

Nicht nur jede Instanz hat ein Feld pi, es hat auch den Wert Null.

pi ist eine konstante Wertdefinition. Der "Accessor" gibt nur die Konstante zurück.

Dies kann unter den Bedingungen der separaten Kompilierung und Inlining Probleme verursachen, wenn Sie sich stark genug bemühen.

{ 
    private final int pi; 
    flags: ACC_PRIVATE, ACC_FINAL 

    public final int pi(); 
    flags: ACC_PUBLIC, ACC_FINAL 
    Code: 
     stack=1, locals=1, args_size=1 
     0: iconst_3  
     1: ireturn  
     LocalVariableTable: 
     Start Length Slot Name Signature 
       0  2  0 this LFoo; 
     LineNumberTable: 
     line 8: 0 

    public Foo(); 
    flags: ACC_PUBLIC 
    Code: 
     stack=1, locals=1, args_size=1 
     0: aload_0  
     1: invokespecial #14     // Method java/lang/Object."<init>":()V 
     4: return   
     LocalVariableTable: 
     Start Length Slot Name Signature 
       0  5  0 this LFoo; 
     LineNumberTable: 
     line 13: 0 
} 

einfach, mich zu überzeugen, bei der Reflexion:

scala> res5.tail 
res16: Iterable[reflect.runtime.universe.Symbol] = List(value pi) 

scala> res5.last.asTerm.isAccessor 
res18: Boolean = false 

scala> res5.head.asTerm.isAccessor 
res19: Boolean = true 

scala> res0 reflectField res5.last.asTerm 
res21: reflect.runtime.universe.FieldMirror = field mirror for Foo.pi (bound to [email protected]) 

scala> res21.get 
res22: Any = 0