簡體   English   中英

為什么隱式值類有額外的方法調用?

[英]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不會在foopublic 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM