class Foo {
final val pi = 3
}
Hat jedes Objekt Foo
ein Element pi
? Sollte ich also pi
in das Begleitobjekt setzen?Erhöhen Endwerte die Objektgröße?
class Foo {
final val pi = 3
}
Hat jedes Objekt Foo
ein Element pi
? Sollte ich also pi
in das Begleitobjekt setzen?Erhöhen Endwerte die Objektgröße?
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.
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