class Foo {
final val pi = 3
}
Foo
オブジェクトにはいずれもpi
メンバーがありますか?したがって、私はpi
をコンパニオンオブジェクトに入れるべきですか?最終的な値はオブジェクトのサイズを増やしますか?
class Foo {
final val pi = 3
}
Foo
オブジェクトにはいずれもpi
メンバーがありますか?したがって、私はpi
をコンパニオンオブジェクトに入れるべきですか?最終的な値はオブジェクトのサイズを増やしますか?
メモリフットプリントが懸念される場合は、このフィールドをコンパニオンオブジェクトに移動することを検討してください。
はい、クラスFoo
のインスタンスはすべてpi
の値になります.Scalaコンパイラはこの宣言を削除しません。 JVMリフレクションでは、クラスメンバーの最終的な修飾子を削除できます。Unsafe
オブジェクトでは、これらを変更することもできます。したがって、Scalaコンパイラはこのフィールドを削除することで驚くべき結果をもたらすコードを生成する可能性があるため、この最適化は適用されません。実際に
...
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
...
、いくつかのコンパイラ変換(例えば特殊化)もアンダーフード部材に最終的な改質を除去するかもしれないので、Scalaのコードでfinal
を感じるものは、バイトコードレベルでfinal
ないかもしれません。
この
:class Foo[@specialized T] {
final val pi: T = null.asInstanceOf[T]
}
になる:上記
...
public final T pi;
flags: ACC_PUBLIC, ACC_FINAL
Signature: #9 // TT;
public T pi();
flags: ACC_PUBLIC
LineNumberTable:
line 243: 0
...
、pi
アクセサメソッド(すなわち、そのゲッタ)はもはや最終あります。
また、Oracle JVMのJITは実行時にメモリ内のオブジェクト表現からこのメンバを削除しません - 32ビットJVM上のFoo
オブジェクトの実行時サイズは16バイトです(8バイトのオブジェクトヘッダー+ 4バイト整数フィールドの場合、8バイトの境界に丸められます)。しかし、JITは、最終フィールドからの一定値をコードの一部にインライン化して、一部のフィールド書き込みを排除することにします。
すべてのインスタンスにフィールドpi
があるだけでなく、値はゼロになります。
pi
は定数値の定義です。 「アクセサ」は定数を返します。
これは、十分に試してみると、別のコンパイルとインライン展開の条件で問題を引き起こす可能性があります。
{
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
}
ただ、反射時に、自分自身を納得させる:
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