risposta

4

Se si è preoccupati dell'impronta di memoria, si potrebbe prendere in considerazione lo spostamento di questo campo nell'oggetto associato.

Sì, ogni istanza della classe Foo avrà il valore pi - il compilatore Scala non eliminerà questa dichiarazione. La riflessione JVM consente di rimuovere i modificatori finali sui membri della classe e l'oggetto Unsafe consente anche di modificarli. Quindi, il compilatore Scala potrebbe produrre codice con risultati sorprendenti rimuovendo questo campo, quindi questa ottimizzazione non viene applicata.

... 
    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 
... 

Infatti, alcune trasformazioni del compilatore (ad esempio specializzazione) potrebbe anche rimuovere i modificatori finali sui membri sotto il cofano, in modo da qualcosa che si sente final in codice Scala potrebbe non essere final a livello bytecode.

Questo:

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

diventa:

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


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

Sopra, il metodo pi di accesso (cioè il suo getter) non è più finale.

E nemmeno il JIT in Oracle JVM rimuove questo membro dalla rappresentazione oggetto in memoria in fase di esecuzione - la dimensione di runtime dell'oggetto Foo su una JVM a 32 bit sarà di 16 byte (intestazione di oggetto 8 byte + 4 byte per un campo intero, arrotondato a un limite di 8 byte). Il JIT potrebbe, tuttavia, decidere di allineare il valore costante del campo finale in parti del codice, in modo che alcune scritture sul campo vengano eliminate.

3

Non solo ogni istanza avrà un campo pi, avrà valore zero.

pi è una definizione di valore costante. L '"accessor" restituisce solo la costante.

Questo può causare problemi in condizioni di compilazione e inlining separate, se ci provate abbastanza.

{ 
    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 
} 

Solo per convincermi, riflettendoci:

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