版本: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
block 引用>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/