ScalaのTraitをjavapしてみたメモ
Traitがどんな感じでJavaのバイトコードに落ちているのか興味があったので試してみた。
komamitsu@carrot ~/lab/scala/traitsample2 $ scala -version Scala code runner version 2.9.1.final -- Copyright 2002-2011, LAMP/EPFL
- Hello.scala
trait T1 { val age:Int val name:String } trait T2 { def hello(name:String) = println("hello " + name) } class C extends T1 with T2 { val age = 42 val name = "komamitsu" }
でjavapした結果がこれ
komamitsu@carrot ~/lab/scala/traitsample2 $ javap -private -c T1 Compiled from "Hello.scala" public interface T1{ public abstract int age(); public abstract java.lang.String name(); } komamitsu@carrot ~/lab/scala/traitsample2 $ javap -private -c T2 Compiled from "Hello.scala" public interface T2 extends scala.ScalaObject{ public abstract void hello(java.lang.String); } komamitsu@carrot ~/lab/scala/traitsample2 $ javap -private -c T2\$class Compiled from "Hello.scala" public abstract class T2$class extends java.lang.Object{ public static void hello(T2, java.lang.String); Code: 0: getstatic #11; //Field scala/Predef$.MODULE$:Lscala/Predef$; 3: new #14; //class scala/collection/mutable/StringBuilder 6: dup 7: invokespecial #18; //Method scala/collection/mutable/StringBuilder."<init>":()V 10: ldc #20; //String hello 12: invokevirtual #24; //Method scala/collection/mutable/StringBuilder.append:(Ljava/lang/Object;)Lscala/collection/mutable/StringBuilder; 15: aload_1 16: invokevirtual #24; //Method scala/collection/mutable/StringBuilder.append:(Ljava/lang/Object;)Lscala/collection/mutable/StringBuilder; 19: invokevirtual #28; //Method scala/collection/mutable/StringBuilder.toString:()Ljava/lang/String; 22: invokevirtual #32; //Method scala/Predef$.println:(Ljava/lang/Object;)V 25: return public static void $init$(T2); Code: 0: return } komamitsu@carrot ~/lab/scala/traitsample2 $ javap -private -c C Compiled from "Hello.scala" public class C extends java.lang.Object implements T1,T2,scala.ScalaObject{ private final int age; private final java.lang.String name; public void hello(java.lang.String); Code: 0: aload_0 1: aload_1 2: invokestatic #15; //Method T2$class.hello:(LT2;Ljava/lang/String;)V 5: return public int age(); Code: 0: aload_0 1: getfield #23; //Field age:I 4: ireturn public java.lang.String name(); Code: 0: aload_0 1: getfield #26; //Field name:Ljava/lang/String; 4: areturn public C(); Code: 0: aload_0 1: invokespecial #32; //Method java/lang/Object."<init>":()V 4: aload_0 5: invokestatic #36; //Method T2$class.$init$:(LT2;)V 8: aload_0 9: bipush 42 11: putfield #23; //Field age:I 14: aload_0 15: ldc #38; //String komamitsu 17: putfield #26; //Field name:Ljava/lang/String; 20: return }
ということで、Java的には以下のような感じになっているみたい。
- valなどのメンバー変数について
- アクセサはTraitのInterface側に
- 変数の実体は継承したClass側に作成される
- defについて
- TraitのInterface側に呼び出し口が作成される
- 実装はInterfaceを継承しているClass側に作成される(この辺はJavaの普通のInterfaceの実装と同じ)
- ただし実質的な処理はTrait InterfaceのInner Classにstatic methodが出来ているので、それを呼び出すだけ