Ответ 1
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
...
Мы видим, что scalac фактически генерирует методы в 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
of 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
поможет вам в диагностике конкретной проблемы.