Trả lời

4

Nếu bạn lo ngại về dung lượng bộ nhớ, bạn có thể xem xét di chuyển trường này vào đối tượng đồng hành.

Có, mọi trường hợp của lớp Foo sẽ có giá trị pi - trình biên dịch Scala sẽ không loại bỏ tuyên bố này. Sự phản chiếu JVM cho phép bạn loại bỏ các biến tố cuối cùng trên các thành viên của lớp và đối tượng Unsafe thậm chí cho phép sửa đổi chúng. Vì vậy, trình biên dịch Scala có thể tạo mã với kết quả đáng ngạc nhiên bằng cách loại bỏ trường này, vì vậy tối ưu hóa này không được áp dụng.

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

Trong thực tế, một số biến đổi trình biên dịch (ví dụ chuyên môn) thậm chí có thể loại bỏ từ bổ nghĩa cuối cùng về thành viên dưới-the-hood, vì vậy một cái gì đó mà cảm thấy final trong mã Scala có thể không phải final vào mức độ bytecode.

này:

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

trở thành:

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


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

Ở trên, phương pháp pi accessor (ví dụ: getter của nó) không còn thức.

Và JIT trong Oracle JVM sẽ không xóa thành viên này khỏi biểu diễn đối tượng trong bộ nhớ khi chạy - kích thước thời gian chạy của đối tượng Foo trên JVM 32 bit sẽ là 16 byte (8 byte đối tượng tiêu đề + 4 byte cho trường số nguyên, được làm tròn thành ranh giới 8 byte). JIT có thể, tuy nhiên, quyết định nội tuyến giá trị không đổi từ trường cuối cùng vào các phần của mã, để một số trường ghi được loại bỏ.

3

Không chỉ mọi trường hợp đều có trường pi, trường sẽ có giá trị bằng 0.

pi là định nghĩa giá trị không đổi. "Accessor" chỉ trả về hằng số.

Điều này có thể gây ra các sự cố trong điều kiện biên dịch và nội tuyến riêng biệt, nếu bạn cố gắng hết sức.

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

Chỉ cần để thuyết phục bản thân mình, sau khi phản ánh:

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