Scala 2.9.1.RC1
Позвольте представить вам нашего друга :javap
в REPL, который может быть полезен для диагностики ошибок. Сначала мы определим класс,
scala> abstract class MyOrdered extends Ordered[MyOrdered] {
| def id: Int
| def compare(that : MyOrdered) : Int =
| if (that==null) 1 else (id-that.id)
| }
defined class MyOrdered
А затем попросите увидеть байт-код JVM,
scala> :javap -v MyOrdered
Compiled from "<console>"
public abstract class MyOrdered extends java.lang.Object implements scala.math.Ordered,scala.ScalaObject
...
** I'm skipping lots of things here: $less, $lessEq, ... **
...
public boolean $greater(java.lang.Object);
Code:
Stack=2, Locals=2, Args_size=2
0: aload_0
1: aload_1
2: invokestatic #19; //Method scala/math/Ordered$class.$greater:(Lscala/math/Ordered;Ljava/lang/Object;)Z
5: ireturn
LineNumberTable:
line 7: 0
...
public abstract int id();
public int compare(MyOrdered);
Code:
Stack=2, Locals=2, Args_size=2
0: aload_1
1: ifnonnull 8
4: iconst_1
5: goto 17
8: aload_0
9: invokevirtual #38; //Method id:()I
12: aload_1
13: invokevirtual #38; //Method id:()I
16: isub
17: ireturn
LineNumberTable:
line 10: 0
...
Мы видим, что скаляр на самом деле генерирует методы в MyOrdered
, соответствующие тем конкретным в черте Ordered
. Например, метод >
переводится в $greater
и в основном просто вызывает scala/math/Ordered$class.$greater
. Если мы хотим, мы можем теперь искать байт-код для конкретных определений черт,
scala> :javap -v scala.math.Ordered$class
Compiled from "Ordered.scala"
public abstract class scala.math.Ordered$class extends java.lang.Object
...
public static boolean $greater(scala.math.Ordered, java.lang.Object);
Code:
Stack=2, Locals=2, Args_size=2
0: aload_0
1: aload_1
2: invokeinterface #12, 2; //InterfaceMethod scala/math/Ordered.compare:(Ljava/lang/Object;)I
7: iconst_0
8: if_icmple 15
11: iconst_1
12: goto 16
15: iconst_0
16: ireturn
LineNumberTable:
line 46: 0
...
Наконец, давайте проверим вашу гипотезу о том, что подкласс M
из MyOrdered
получает полную копию всех методов
scala> class M extends MyOrdered { def id = 2 }
defined class M
scala> :javap -v M
Compiled from "<console>"
public class M extends MyOrdered implements scala.ScalaObject
....
** No extra methods besides id **
....
Нет, похоже, здесь нет дублирования кода.
В заключение,
Scalac немного творит магию с помощью конкретных методов, поэтому не пытайтесь наследовать их от Java. Абстрактные классы должны быть в порядке.
JVM изначально не поддерживает имена символических методов, одноэлементные объекты Scala и черты с конкретными методами, поэтому компилятору Scala необходимо выполнить некоторый перевод и использовать зарезервированный символ $.
Если у вас все еще есть проблемы с взаимодействием Java, надеюсь, :javap
поможет вам в диагностике конкретной проблемы.