[英]Why do implicit value classes have an extra method invocation?
我正在檢查隱式類生成的字節碼,並希望與擴展AnyVal
時生成的內容進行比較。
object Example1 {
class Wrapper(val self: Int) extends AnyVal {
def add(n: Int): Int = self + n
}
def foo(w: Wrapper): Wrapper = new Wrapper(w.add(42))
}
字節碼的(相關部分):
scala>:javap Example1
[...]
public int foo(int);
descriptor: (I)I
flags: ACC_PUBLIC
Code:
stack=3, locals=2, args_size=2
0: getstatic #19 // Field Example1$Wrapper$.MODULE$:LExample1$Wrapper$;
3: iload_1
4: bipush 42
6: invokevirtual #23 // Method Example1$Wrapper$.add$extension:(II)I
9: ireturn
LocalVariableTable:
Start Length Slot Name Signature
0 10 0 this LExample1$;
0 10 1 w I
LineNumberTable:
line 11: 3
[...]
implicit
: object Example2 {
implicit class Wrapper(val self: Int) extends AnyVal {
def add(n: Int): Int = self + n
}
def foo(w: Wrapper): Wrapper = w.add(42)
}
字節碼的(相關部分):
scala>:javap Example2
[...]
public int Wrapper(int);
descriptor: (I)I
flags: ACC_PUBLIC
Code:
stack=1, locals=2, args_size=2
0: iload_1
1: ireturn
LocalVariableTable:
Start Length Slot Name Signature
0 2 0 this LExample2$;
0 2 1 self I
LineNumberTable:
line 9: 0
public int foo(int);
descriptor: (I)I
flags: ACC_PUBLIC
Code:
stack=4, locals=2, args_size=2
0: aload_0
1: getstatic #23 // Field Example2$Wrapper$.MODULE$:LExample2$Wrapper$;
4: iload_1
5: bipush 42
7: invokevirtual #27 // Method Example2$Wrapper$.add$extension:(II)I
10: invokevirtual #29 // Method Wrapper:(I)I
13: ireturn
LocalVariableTable:
Start Length Slot Name Signature
0 14 0 this LExample2$;
0 14 1 w I
LineNumberTable:
line 12: 0
[...]
作為擴展AnyVal
的結果,在伴隨對象上調用add
調用,並且在兩個版本中,類型Wrapper
不會在foo
( public int foo(int);
)的類型簽名中顯示。
Hovewer,在第二個版本中,在返回之前有一個調用: 10: invokevirtual #29
。 它調用public int Wrapper(int);
看似什么也沒做。 (雖然我可能錯了,因為我沒有太多閱讀字節碼的經驗)
所以問題是,這個電話有什么意義? 不能省略嗎?
問題是你的代碼片段不相同。 隱式類Foo
被編譯/ desugared到類Foo
和隱式轉換方法Foo
。 這也是隱式類(當前)不能達到頂級水平的原因。
所以你的第一個片段應該是:
object Example1 {
class Wrapper(val self: Int) extends AnyVal {
def add(n: Int): Int = self + n
}
def Wrapper(self: Int): Wrapper = new Wrapper(self)
def foo(w: Wrapper): Wrapper = Wrapper(w.add(42))
}
如果可能,編譯器將擦除對值類構造函數的調用。 但它不會刪除對Wrapper
方法的調用,無論是否隱含。
我想JVM中的JIT編譯器最終會刪除該方法調用。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.