class Foo {
final val pi = 3
}
Czy każdy obiekt Foo
ma element pi
? Czy w związku z tym powinienem wstawić pi
w obiekcie towarzyszącym?Czy ostateczne vals zwiększają rozmiar obiektu?
class Foo {
final val pi = 3
}
Czy każdy obiekt Foo
ma element pi
? Czy w związku z tym powinienem wstawić pi
w obiekcie towarzyszącym?Czy ostateczne vals zwiększają rozmiar obiektu?
Jeśli martwisz się o ślad pamięci, możesz rozważyć przeniesienie tego pola do obiektu towarzyszącego.
Tak, każde wystąpienie klasy Foo
będzie miało wartość pi
- kompilator Scali nie wyeliminuje tej deklaracji. Odbicie JVM pozwala na usunięcie ostatecznych modyfikatorów na elementach klas, a obiekt Unsafe
pozwala nawet na ich modyfikację. Tak więc - kompilator Scala może wytworzyć kod z zaskakującymi wynikami, usuwając to pole, więc ta optymalizacja nie jest stosowana.
...
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
...
W rzeczywistości niektóre transformacje kompilatora (np specjalizacja) może nawet usunąć końcowe modyfikatorów na członków under-the-kaptur, więc coś, co czuje final
w kodzie Scala nie może być final
na poziomie kodu bajtowego.
to:
class Foo[@specialized T] {
final val pi: T = null.asInstanceOf[T]
}
postać:
...
public final T pi;
flags: ACC_PUBLIC, ACC_FINAL
Signature: #9 // TT;
public T pi();
flags: ACC_PUBLIC
LineNumberTable:
line 243: 0
...
powyżej, sposób pi
dostępowe (czyli jej gettera) nie jest ostateczny.
JIT w JVM Oracle nie usunie tego elementu z reprezentacji obiektu w pamięci w środowisku wykonawczym - rozmiar środowiska wykonawczego obiektu Foo
na 32-bitowej maszynie JVM będzie wynosił 16 bajtów (8 bajtów nagłówka obiektu + 4 bajty dla pola liczby całkowitej, zaokrąglone do granicy 8 bajtów). JIT może jednak zdecydować o wstawieniu wartości stałej z pola końcowego do części kodu, aby niektóre zapisy w terenie zostały wyeliminowane.
Nie tylko każda instancja ma pole pi
, będzie miała wartość zero.
pi
jest definicją wartości stałej. "Accessor" po prostu zwraca stałą.
Może to powodować problemy w warunkach oddzielnej kompilacji i wstawiania, jeśli będziesz wystarczająco mocno się starał.
{
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
}
Wystarczy, aby przekonać się, na refleksję:
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