ということを言ったので、Scalaのコードもjavapしようと思いました。
もちろんscalacしてからjavapしてもよいのですが、ScalaはなんとREPLからjavapできると知りました。
REPL で使える :javap コマンドのオプションはコマンドラインの javap(1)... - tnoda-scala
すばらしい記事だと感じました。ありがとうございます!
なので、REPLでHelloWorldを作成してjavapしたいと思います。
scala> object HelloWorldInScala { | def main(args: Array[String]) : Unit = { | printf("Hello World!") | } | } defined object HelloWorldInScala
REPLでは:javapで実行できます。
scala> :javap HelloWorldInScala
バイナリ・ファイルHelloWorldInScalaにHelloWorldInScala$が含まれています
Size 912 bytes
MD5 checksum 5dfd2db5d76bd3264d1907e6a92a5fbb
Compiled from "<console>"
public class HelloWorldInScala$
minor version: 0
major version: 50
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Utf8 HelloWorldInScala$
#2 = Class #1 // HelloWorldInScala$
#3 = Utf8 java/lang/Object
#4 = Class #3 // java/lang/Object
#5 = Utf8 <console>
#6 = Utf8 MODULE$
#7 = Utf8 LHelloWorldInScala$;
#8 = Utf8 <clinit>
#9 = Utf8 ()V
#10 = Utf8 <init>
#11 = NameAndType #10:#9 // "<init>":()V
#12 = Methodref #2.#11 // HelloWorldInScala$."<init>":()V
#13 = Utf8 main
#14 = Utf8 ([Ljava/lang/String;)V
#15 = Utf8 scala/Predef$
#16 = Class #15 // scala/Predef$
#17 = Utf8 Lscala/Predef$;
#18 = NameAndType #6:#17 // MODULE$:Lscala/Predef$;
#19 = Fieldref #16.#18 // scala/Predef$.MODULE$:Lscala/Predef$;
#20 = Utf8 Hello World!
#21 = String #20 // Hello World!
#22 = Utf8 genericWrapArray
#23 = Utf8 (Ljava/lang/Object;)Lscala/collection/mutable/WrappedArray;
#24 = NameAndType #22:#23 // genericWrapArray:(Ljava/lang/Object;)Lscala/collection/mutable/WrappedArray;
#25 = Methodref #16.#24 // scala/Predef$.genericWrapArray:(Ljava/lang/Object;)Lscala/collection/mutable/WrappedArray;
#26 = Utf8 printf
#27 = Utf8 (Ljava/lang/String;Lscala/collection/Seq;)V
#28 = NameAndType #26:#27 // printf:(Ljava/lang/String;Lscala/collection/Seq;)V
#29 = Methodref #16.#28 // scala/Predef$.printf:(Ljava/lang/String;Lscala/collection/Seq;)V
#30 = Utf8 this
#31 = Utf8 args
#32 = Utf8 [Ljava/lang/String;
#33 = Methodref #4.#11 // java/lang/Object."<init>":()V
#34 = NameAndType #6:#7 // MODULE$:LHelloWorldInScala$;
#35 = Fieldref #2.#34 // HelloWorldInScala$.MODULE$:LHelloWorldInScala$;
#36 = Utf8
#37 = Class #36 //
#38 = Utf8 $line4/$read
#39 = Class #38 // $line4/$read
#40 = Utf8
#41 = Utf8
#42 = Class #41 //
#43 = Utf8 HelloWorldInScala$
#44 = Utf8 Code
#45 = Utf8 LocalVariableTable
#46 = Utf8 LineNumberTable
#47 = Utf8 SourceFile
#48 = Utf8 InnerClasses
#49 = Utf8 Scala
{
public static final HelloWorldInScala$ MODULE$;
descriptor: LHelloWorldInScala$;
flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
public static {};
descriptor: ()V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=1, locals=0, args_size=0
0: new #2 // class HelloWorldInScala$
3: invokespecial #12 // Method "<init>":()V
6: return
public void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC
Code:
stack=4, locals=2, args_size=2
0: getstatic #19 // Field scala/Predef$.MODULE$:Lscala/Predef$;
3: ldc #21 // String Hello World!
5: getstatic #19 // Field scala/Predef$.MODULE$:Lscala/Predef$;
8: iconst_0
9: anewarray #4 // class java/lang/Object
12: invokevirtual #25 // Method scala/Predef$.genericWrapArray:(Ljava/lang/Object;)Lscala/collection/mutable/WrappedArray;
15: invokevirtual #29 // Method scala/Predef$.printf:(Ljava/lang/String;Lscala/collection/Seq;)V
18: return
LocalVariableTable:
Start Length Slot Name Signature
0 19 0 this LHelloWorldInScala$;
0 19 1 args [Ljava/lang/String;
LineNumberTable:
line 9: 0
public HelloWorldInScala$();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #33 // Method java/lang/Object."<init>":()V
4: aload_0
5: putstatic #35 // Field MODULE$:LHelloWorldInScala$;
8: return
LocalVariableTable:
Start Length Slot Name Signature
0 9 0 this LHelloWorldInScala$;
LineNumberTable:
line 15: 0
}
SourceFile: "<console>"
InnerClasses:
public static #40= #37 of #39; //=class of class $line4/$read
public static #40= #42 of #37; //=class of class
public static #43= #2 of #42; //HelloWorldInScala$=class HelloWorldInScala$ of class
Error: unknown attribute
Scala: length = 0x0
デフォルトでは-vした結果を出力するようです。さて、JavaのHelloWorldと全然違う出力となりました。objectを使っている影響もあります。
HelloWorldInScala$という内部クラスを作っているようです。さすがにjavapで処理の流れで追うのはしんどくなってきました。一度scalacしてクラスファイルを生成し、そのクラスファイルをデコンパイルしてJavaコードにしてみます。デコンパイルはJD(http://jd.benow.ca/)を使いました。
import scala.reflect.ScalaSignature; @ScalaSignature(bytes="\006\001\025:Q!\001\002\t\002\025\t\021\003S3mY><vN\0357e\023:\0346-\0317b\025\005\031\021a\002\037f[B$\030PP\002\001!\t1q!D\001\003\r\025A!\001#\001\n\005EAU\r\0347p/>\024H\016Z%o'\016\fG.Y\n\003\017)\001\"a\003\b\016\0031Q\021!D\001\006g\016\fG.Y\005\003\0371\021a!\0218z%\0264\007\"B\t\b\t\003\021\022A\002\037j]&$h\bF\001\006\021\025!r\001\"\001\026\003\021i\027-\0338\025\005YI\002CA\006\030\023\tABB\001\003V]&$\b\"\002\016\024\001\004Y\022\001B1sON\0042a\003\017\037\023\tiBBA\003BeJ\f\027\020\005\002 E9\0211\002I\005\003C1\ta\001\025:fI\0264\027BA\022%\005\031\031FO]5oO*\021\021\005\004") public final class HelloWorldInScala { public static void main(String[] paramArrayOfString) { HelloWorldInScala..MODULE$.main(paramArrayOfString); } } import scala.Predef.; public final class HelloWorldInScala$ { public static final MODULE$; static { new (); } public void main(String[] args) { Predef..MODULE$.printf("Hello World!", Predef..MODULE$.genericWrapArray(new Object[0])); } private HelloWorldInScala$() { MODULE$ = this; } }
内部クラスHelloWorldInScala$では、staticイニシャライザで自分をnewして、static final定数に代入しているようです。メインクラスHelloWorldInScalaのmain()メソッド内部クラスHelloWorldInScala$のインスタンスのmain()というメソッドを呼び出します。内部クラスのmain()メソッドではscala.Predef#printf()メソッドを呼び出すので"Hello World!"が出力されるというわけです。