java - Scala @specialized 注解无限递归?

标签 java scala annotations specialized-annotation

版本:scala 2.11.8

我在继承中定义了一个具有特殊类型和重写方法的类:

class Father[@specialized(Int) A]{
  def get(from: A): A = from
}

class Son extends Father[Int]{
  override def get(from: Int): Int = {
    println("Son.get")
    super.get(from)
  }
}

new Son().get(1)  // will cause infinite recursion

那么,如何通过专门的注解重用父类(super class)的方法呢?

最佳答案

摘自文章Quirks of Scala Specialization :

Avoid super calls

Qualified super calls are (perhaps fundamentally) broken with specialization. Rewiring the super-accessor methods properly in the specialization phase is a nightmare that has not been solved so far. So, avoid them like the plague, at least for now. In particular, stackable modifications pattern will not work with it well.

所以这很可能是编译器错误,一般来说您不应该使用 super调用 Scala 特化。


经过一番调查:

javap -c Son.class

public class Son extends Father$mcI$sp {
  public int get(int);
    Code:
       0: aload_0
       1: iload_1
       2: invokevirtual #14                 // Method get$mcI$sp:(I)I
       5: ireturn

  public int get$mcI$sp(int);
    Code:
       0: getstatic     #23                 // Field scala/Predef$.MODULE$:Lscala/Predef$;
       3: ldc           #25                 // String Son.get
       5: invokevirtual #29                 // Method scala/Predef$.println:(Ljava/lang/Object;)V
       8: aload_0
       9: iload_1
      10: invokespecial #31                 // Method Father$mcI$sp.get:(I)I
      13: ireturn

Son.get(int)来电 Son.get$mcI$sp(int)变成 Father$mcI$sp.get(int) :

javap -c Father\$mcI\$sp.class 

public class Father$mcI$sp extends Father<java.lang.Object> {
  public int get(int);
    Code:
       0: aload_0
       1: iload_1
       2: invokevirtual #12                 // Method get$mcI$sp:(I)I
       5: ireturn

  public int get$mcI$sp(int);
    Code:
       0: iload_1
       1: ireturn

看来我们已经找到原因了 - Father$mcI$sp.get(int)虚拟调用get$mcI$sp ,在 Son 中重载!这就是导致这里无限递归的原因。

编译器必须创建方法 get 的专门版本这是 get$mcI$sp ,以支持 Father[T] 的非专业通用版本,不幸的是,这使得不可能拥有 super与专门的类进行调用。


现在更改 Father 后会发生什么成为一个特质(Scala 2.12):

javap -c Son.class

public class Son implements Father$mcI$sp {

  public int get$mcI$sp(int);
    Code:
       0: getstatic     #25                 // Field scala/Predef$.MODULE$:Lscala/Predef$;
       3: ldc           #27                 // String Son.get
       5: invokevirtual #31                 // Method scala/Predef$.println:(Ljava/lang/Object;)V
       8: aload_0
       9: iload_1
      10: invokestatic  #37                 // Method scala/runtime/BoxesRunTime.boxToInteger:(I)Ljava/lang/Integer;
      13: invokestatic  #43                 // InterfaceMethod Father.get$:(LFather;Ljava/lang/Object;)Ljava/lang/Object;
      16: invokestatic  #47                 // Method scala/runtime/BoxesRunTime.unboxToInt:(Ljava/lang/Object;)I
      19: ireturn

看起来不像调用 get$mcI$sp在父类中,它调用静态方法 Father.get$ :

javap -c Father.class 

public interface Father<A> {
  public static java.lang.Object get$(Father, java.lang.Object);
    Code:
       0: aload_0
       1: aload_1
       2: invokespecial #17                 // InterfaceMethod get:(Ljava/lang/Object;)Ljava/lang/Object;
       5: areturn

  public A get(A);
    Code:
       0: aload_1
       1: areturn

  public static int get$mcI$sp$(Father, int);
    Code:
       0: aload_0
       1: iload_1
       2: invokespecial #26                 // InterfaceMethod get$mcI$sp:(I)I
       5: ireturn

  public int get$mcI$sp(int);
    Code:
       0: aload_0
       1: iload_1
       2: invokestatic  #33                 // Method scala/runtime/BoxesRunTime.boxToInteger:(I)Ljava/lang/Integer;
       5: invokeinterface #17,  2           // InterfaceMethod get:(Ljava/lang/Object;)Ljava/lang/Object;
      10: invokestatic  #37                 // Method scala/runtime/BoxesRunTime.unboxToInt:(Ljava/lang/Object;)I
      13: ireturn

这里有趣的是,它看起来像 get方法没有获得真正的特化,因为它必须将值装箱 get$mcI$sp ,这可能是一个错误,或者可能是 Scala 2.12 中删除了对特征的特化支持。

关于java - Scala @specialized 注解无限递归?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41328949/

相关文章:

java - 发送邮件 : java.net.SocketException:网络无法访问:连接

json - Scala Play Json - 如何从数组中的元素读取单个元素?

class - 在 Scala 中获取 Main 类

spring-mvc - SpringSecurity 多个命名空间和安全注解。大困惑

java - 在扩展类上声明proporder

java - 如何正确地将 JSP 放入 WEB-INF 文件夹中?

java - 关于 Servlet 的问题

java - 了解 : public static <T> int max(List<T> list, 比较器<? super T> c) 请

Scala 对象被屏蔽为方法与实际方法(Stream.cons)

swift - 我怎么知道 map View 上是否已经有注释