ということを言ったので、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!"が出力されるというわけです。