@雲南犀鳥科技有限公司java
#對象 在搞對象以前,咱們還須要先把啥是對象搞清楚,在Scala裏面,使用object關鍵字,替代class關鍵字的類就叫作對象,不過,它有它本身的限制和特色。app
object Simple { }
咱們編譯 scalac Simple.scala,會獲得Simple.class以及Simple$.class,意思是說scalac會把object生成兩個類麼?咱們先來看Simple.class函數
javap -c -v -private Simple學習
Classfile /Users/Yanne/project/scala/deepscala/Simple.class Last modified 2016-5-13; size 323 bytes MD5 checksum 7c951e41aaf72e2e0540dc79a9261584 Compiled from "Simple.scala" public final class Simple SourceFile: "Simple.scala" RuntimeVisibleAnnotations: 0: #6(#7=s#8) ScalaSig: length = 0x3 05 00 00 minor version: 0 major version: 50 flags: ACC_PUBLIC, ACC_FINAL, ACC_SUPER Constant pool: #1 = Utf8 Simple #2 = Class #1 // Simple #3 = Utf8 java/lang/Object #4 = Class #3 // java/lang/Object #5 = Utf8 Simple.scala #6 = Utf8 Lscala/reflect/ScalaSignature; #7 = Utf8 bytes #8 = Utf8 M9Q!\t\taaU5na2,'\"Aq*W;z}\ra!I!AB*j[BdWA1BD)\tQ\"AtGd-\t1I\=SKDQ!EI\taP5oSRtD#A #9 = Utf8 SourceFile #10 = Utf8 RuntimeVisibleAnnotations #11 = Utf8 ScalaSig { }
Simple類變成final的了,其餘的咱們啥都沒看到,也就是說此類是不能被擴展的,那麼**javap -c -v -private Simple$**呢?this
Classfile /Users/Yanne/project/scala/deepscala/Simple$.class Last modified 2016-5-13; size 374 bytes MD5 checksum 1f50323fc335e68561440a8e37e8d0da Compiled from "Simple.scala" public final class Simple$ SourceFile: "Simple.scala" ScalaInlineInfo: length = 0x9 01 01 00 01 00 0A 00 09 01 Scala: length = 0x0 minor version: 0 major version: 50 flags: ACC_PUBLIC, ACC_FINAL, ACC_SUPER Constant pool: #1 = Utf8 Simple$ #2 = Class #1 // Simple$ #3 = Utf8 java/lang/Object #4 = Class #3 // java/lang/Object #5 = Utf8 Simple.scala #6 = Utf8 MODULE$ #7 = Utf8 LSimple$; #8 = Utf8 <clinit> #9 = Utf8 ()V #10 = Utf8 <init> #11 = NameAndType #10:#9 // "<init>":()V #12 = Methodref #2.#11 // Simple$."<init>":()V #13 = Methodref #4.#11 // java/lang/Object."<init>":()V #14 = NameAndType #6:#7 // MODULE$:LSimple$; #15 = Fieldref #2.#14 // Simple$.MODULE$:LSimple$; #16 = Utf8 this #17 = Utf8 Code #18 = Utf8 LocalVariableTable #19 = Utf8 LineNumberTable #20 = Utf8 SourceFile #21 = Utf8 ScalaInlineInfo #22 = Utf8 Scala { public static final Simple$ MODULE$; flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL public static {}; flags: ACC_PUBLIC, ACC_STATIC Code: stack=1, locals=0, args_size=0 0: new #2 // class Simple$ 3: invokespecial #12 // Method "<init>":()V 6: return private Simple$(); flags: ACC_PRIVATE Code: stack=1, locals=1, args_size=1 0: aload_0 1: invokespecial #13 // Method java/lang/Object."<init>":()V 4: aload_0 5: putstatic #15 // Field MODULE$:LSimple$; 8: return LocalVariableTable: Start Length Slot Name Signature 0 9 0 this LSimple$; LineNumberTable: line 3: 0 }
重點看,public static final Simple$ MODULE$; 以及 private Simple$(); public static {};.net
首先,Simple$的構造器是私有的,可是Simple$提供了一個靜態的公開的常量MODULE$,這是否是和咱們的單列模式很像呢?scala
但是,咱們的Simple類和Simple$之間並無什麼聯繫呀?爲何呢?由於咱們在Simple類中啥都沒有作,如今讓咱們來作點事情。3d
object Simple { def say(){ } }
咱們反編譯來看看代理
javap -c -v -private Simple Classfile /Users/Yanne/project/scala/deepscala/Simple.class Last modified 2016-5-13; size 464 bytes MD5 checksum 8fe08ac15b83be21380cab9bfb5d2d2c Compiled from "Simple.scala" public final class Simple SourceFile: "Simple.scala" RuntimeVisibleAnnotations: 0: #6(#7=s#8) ScalaSig: length = 0x3 05 00 00 minor version: 0 major version: 50 flags: ACC_PUBLIC, ACC_FINAL, ACC_SUPER Constant pool: #1 = Utf8 Simple #2 = Class #1 // Simple #3 = Utf8 java/lang/Object #4 = Class #3 // java/lang/Object #5 = Utf8 Simple.scala #6 = Utf8 Lscala/reflect/ScalaSignature; #7 = Utf8 bytes #8 = Utf8 e9Q!\t\taaU5na2,'\"Aq*W;z}\ra!I!AB*j[BdWA1BD)\tQ\"AtGd-\t1I\=SKDQ!EI\taP5oSRtD#A\t Q9AA M F!\tYq#\t!QK\5u #9 = Utf8 say #10 = Utf8 ()V #11 = Utf8 Simple$ #12 = Class #11 // Simple$ #13 = Utf8 MODULE$ #14 = Utf8 LSimple$; #15 = NameAndType #13:#14 // MODULE$:LSimple$; #16 = Fieldref #12.#15 // Simple$.MODULE$:LSimple$; #17 = NameAndType #9:#10 // say:()V #18 = Methodref #12.#17 // Simple$.say:()V #19 = Utf8 Code #20 = Utf8 SourceFile #21 = Utf8 RuntimeVisibleAnnotations #22 = Utf8 ScalaSig { public static void say(); flags: ACC_PUBLIC, ACC_STATIC Code: stack=1, locals=0, args_size=0 0: getstatic #16 // Field Simple$.MODULE$:LSimple$; 3: invokevirtual #18 // Method Simple$.say:()V 6: return }
咱們看到,Scala對象Simple中的say方法變成了靜態的了,咱們如今用僞代碼來看看say方法到底幹了什麼。code
public static void say(){ Simple$ Simple$.MODULE$; Simple$.say(); }
做用很明顯了,就是去調用Simple$的say方法,先來看看此時的Simple$
Classfile /Users/Yanne/project/scala/deepscala/Simple$.class Last modified 2016-5-13; size 442 bytes MD5 checksum 4fa739988d0dadd6cba59fd9101ef98c Compiled from "Simple.scala" public final class Simple$ SourceFile: "Simple.scala" ScalaInlineInfo: length = 0xE 01 01 00 02 00 0A 00 09 01 00 0D 00 09 01 Scala: length = 0x0 minor version: 0 major version: 50 flags: ACC_PUBLIC, ACC_FINAL, ACC_SUPER Constant pool: #1 = Utf8 Simple$ #2 = Class #1 // Simple$ #3 = Utf8 java/lang/Object #4 = Class #3 // java/lang/Object #5 = Utf8 Simple.scala #6 = Utf8 MODULE$ #7 = Utf8 LSimple$; #8 = Utf8 <clinit> #9 = Utf8 ()V #10 = Utf8 <init> #11 = NameAndType #10:#9 // "<init>":()V #12 = Methodref #2.#11 // Simple$."<init>":()V #13 = Utf8 say #14 = Utf8 this #15 = Methodref #4.#11 // java/lang/Object."<init>":()V #16 = NameAndType #6:#7 // MODULE$:LSimple$; #17 = Fieldref #2.#16 // Simple$.MODULE$:LSimple$; #18 = Utf8 Code #19 = Utf8 LocalVariableTable #20 = Utf8 LineNumberTable #21 = Utf8 SourceFile #22 = Utf8 ScalaInlineInfo #23 = Utf8 Scala { public static final Simple$ MODULE$; flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL public static {}; flags: ACC_PUBLIC, ACC_STATIC Code: stack=1, locals=0, args_size=0 0: new #2 // class Simple$ 3: invokespecial #12 // Method "<init>":()V 6: return public void say(); flags: ACC_PUBLIC Code: stack=0, locals=1, args_size=1 0: return LocalVariableTable: Start Length Slot Name Signature 0 1 0 this LSimple$; LineNumberTable: line 2: 0 private Simple$(); flags: ACC_PRIVATE Code: stack=1, locals=1, args_size=1 0: aload_0 1: invokespecial #15 // Method java/lang/Object."<init>":()V 4: aload_0 5: putstatic #17 // Field MODULE$:LSimple$; 8: return LocalVariableTable: Start Length Slot Name Signature 0 9 0 this LSimple$; LineNumberTable: line 5: 0 }
咱們能夠看到,在Simple$類中存在一個靜態屬性MODULE$,而這個屬性的類型是Simple$,同時,在Simple$類中存在一個pulic的方法say.
因此,從上面的狀況來看,如今的Simple對象反而就像是Simple$的一個代理了,真正幹活的是Simple$類。
其實咱們能夠進行類推,只要把上述的say方法的簽名換成def main(args:Array[String]) 就能夠獲得咱們的程序入口了。
object Simple { def main(args:Array[String]){ } }
javap -c -v -private Simple
Classfile /Users/Yanne/project/scala/deepscala/Simple.class Last modified 2016-5-13; size 561 bytes MD5 checksum e024e8adf8cb3a03df9e342eb7bdd43e Compiled from "Simple.scala" h\t\tC final class Simple #9 = Utf8 main #10 = Utf8 ([Ljava/lang/String;)V #11 = Utf8 Simple$ #12 = Class #11 // Simple$ #13 = Utf8 MODULE$ #14 = Utf8 LSimple$; #15 = NameAndType #13:#14 // MODULE$:LSimple$; #16 = Fieldref #12.#15 // Simple$.MODULE$:LSimple$; #17 = NameAndType #9:#10 // main:([Ljava/lang/String;)V #18 = Methodref #12.#17 // Simple$.main:([Ljava/lang/String;)V #2 = Class #1 // Simple #19 = Utf8 Code/lang/Object #20 = Utf8 SourceFile // java/lang/Object #21 = Utf8 RuntimeVisibleAnnotations #22 = Utf8 ScalaSigeflect/ScalaSignature; { #7 = Utf8 bytes public static void main(java.lang.String[]);q*W;z}\ra!I!AB*j[BdWA1BD)\tQ\"AtGd flags: ACC_PUBLIC, ACC_STATIC Code: Q9AA stack=2, locals=1, args_size=1 0: getstatic #16 // Field Simple$.MODULE$:LSimple$; 3: aload_0 -e\"aC 4: invokevirtual #18 // Method Simple$.main:([Ljava/lang/String;)VeKL!a\t\rM#(/ 7: return }
javap -c -v -private Simple$
Classfile /Users/Yanne/project/scala/deepscala/Simple$.class Last modified 2016-5-13; size 507 bytes MD5 checksum df7c21289480ea8adbbb7d405ffda09f Compiled from "Simple.scala" public final class Simple$ SourceFile: "Simple.scala" ScalaInlineInfo: length = 0xE 01 01 00 02 00 0A 00 09 01 00 0D 00 0E 01 Scala: length = 0x0 minor version: 0 major version: 50 flags: ACC_PUBLIC, ACC_FINAL, ACC_SUPER Constant pool: #1 = Utf8 Simple$ #2 = Class #1 // Simple$ #3 = Utf8 java/lang/Object #4 = Class #3 // java/lang/Object #5 = Utf8 Simple.scala #6 = Utf8 MODULE$ #7 = Utf8 LSimple$; #8 = Utf8 <clinit> #9 = Utf8 ()V #10 = Utf8 <init> #11 = NameAndType #10:#9 // "<init>":()V #12 = Methodref #2.#11 // Simple$."<init>":()V #13 = Utf8 main #14 = Utf8 ([Ljava/lang/String;)V #15 = Utf8 this #16 = Utf8 args #17 = Utf8 [Ljava/lang/String; #18 = Methodref #4.#11 // java/lang/Object."<init>":()V #19 = NameAndType #6:#7 // MODULE$:LSimple$; #20 = Fieldref #2.#19 // Simple$.MODULE$:LSimple$; #21 = Utf8 Code #22 = Utf8 LocalVariableTable #23 = Utf8 LineNumberTable #24 = Utf8 SourceFile #25 = Utf8 ScalaInlineInfo #26 = Utf8 Scala { public static final Simple$ MODULE$; flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL public static {}; flags: ACC_PUBLIC, ACC_STATIC Code: stack=1, locals=0, args_size=0 0: new #2 // class Simple$ 3: invokespecial #12 // Method "<init>":()V 6: return public void main(java.lang.String[]); flags: ACC_PUBLIC Code: stack=0, locals=2, args_size=2 0: return LocalVariableTable: Start Length Slot Name Signature 0 1 0 this LSimple$; 0 1 1 args [Ljava/lang/String; LineNumberTable: line 2: 0 private Simple$(); flags: ACC_PRIVATE Code: stack=1, locals=1, args_size=1 0: aload_0 1: invokespecial #18 // Method java/lang/Object."<init>":()V 4: aload_0 5: putstatic #20 // Field MODULE$:LSimple$; 8: return LocalVariableTable: Start Length Slot Name Signature 0 9 0 this LSimple$; LineNumberTable: line 5: 0 }
到這裏,咱們能夠稍微總結一下,object裏面的方法被編譯成了靜態的方法,同時,真正幹活的是object對象後面的那個家了$的類,其實咱們能夠把這個加了$的類佳做虛構類。
那問題來了,object裏面的屬性又是怎麼回事呢?
object Simple { val name ="Yanne" def main(args:Array[String]){ } }
javap -c -v -private Simple
Classfile /Users/Yanne/project/scala/deepscala/Simple.class \r2CA%\t)CBV]&\"B!AB1sON2aC,\tQCBABeJytes MD5 checksum 8818d17f3a9dd9e42dda2b-_91\"L]1\ta:fI4BA1\tqC #9 = Utf8 main #10 = Utf8 ([Ljava/lang/String;)V #11 = Utf8 Simple$ #12 = Class #11 // Simple$ #13 = Utf8 MODULE$ #14 = Utf8 LSimple$; #15 = NameAndType #13:#14 // MODULE$:LSimple$; #16 = Fieldref #12.#15 // Simple$.MODULE$:LSimple$; #17 = NameAndType #9:#10 // main:([Ljava/lang/String;)V #18 = Methodref #12.#17 // Simple$.main:([Ljava/lang/String;)Vonstant pool: #19 = Utf8 namele #20 = Utf8 ()Ljava/lang/String;imple #21 = NameAndType #19:#20 // name:()Ljava/lang/String; #22 = Methodref #12.#21 // Simple$.name:()Ljava/lang/String; #23 = Utf8 Codele.scala #24 = Utf8 SourceFilelect/ScalaSignature; #25 = Utf8 RuntimeVisibleAnnotations #26 = Utf8 ScalaSigaaU5na2,'\"Aq*W;z}\ra!I!AB*j[BdWA1BD)\tQ\"AtG{-\t1I\=SKDQ!EI\taP5oSRtD#A\tQ9!!C+!a.Y7f+1CA public static void main(java.lang.String[]);\"BA\raM\4 flags: ACC_PUBLIC, ACC_STATIC m\tAA[1wC&Q'RN\4\t\r}9!q Code:#i- stack=2, locals=1, args_size=1 0: getstatic #16 // Field Simple$.MODULE$:LSimple$; 3: aload_0 4: invokevirtual #18 // Method Simple$.main:([Ljava/lang/String;)V 7: return public static java.lang.String name(); flags: ACC_PUBLIC, ACC_STATIC Code: stack=1, locals=0, args_size=0 0: getstatic #16 // Field Simple$.MODULE$:LSimple$; 3: invokevirtual #22 // Method Simple$.name:()Ljava/lang/String; 6: areturn }
從上面編譯結果來看,對應的屬性name已經被編譯成了靜態方法name(),咱們叫作getter,並且name方法執行的內容是Simple$.MODULE$.name()方法,那麼,虛構類中的狀況是怎樣的呢?
javap -c -v -private Simple$
Classfile /Users/Yanne/project/scala/deepscala/Simple$.class Last modified 2016-5-13; size 663 bytes MD5 checksum 88c152f50df4f21b0519526a8f9b55db Compiled from "Simple.scala" public final class Simple$ SourceFile: "Simple.scala" ScalaInlineInfo: length = 0x13 01 01 00 03 00 0A 00 09 01 00 13 00 14 01 00 0D 00 0F 01 Scala: length = 0x0 minor version: 0 major version: 50 flags: ACC_PUBLIC, ACC_FINAL, ACC_SUPER Constant pool: #1 = Utf8 Simple$ #2 = Class #1 // Simple$ #3 = Utf8 java/lang/Object #4 = Class #3 // java/lang/Object #5 = Utf8 Simple.scala #6 = Utf8 MODULE$ #7 = Utf8 LSimple$; #8 = Utf8 <clinit> #9 = Utf8 ()V #10 = Utf8 <init> #11 = NameAndType #10:#9 // "<init>":()V #12 = Methodref #2.#11 // Simple$."<init>":()V #13 = Utf8 name #14 = Utf8 Ljava/lang/String; #15 = Utf8 ()Ljava/lang/String; #16 = NameAndType #13:#14 // name:Ljava/lang/String; #17 = Fieldref #2.#16 // Simple$.name:Ljava/lang/String; #18 = Utf8 this #19 = Utf8 main #20 = Utf8 ([Ljava/lang/String;)V #21 = Utf8 args #22 = Utf8 [Ljava/lang/String; #23 = Methodref #4.#11 // java/lang/Object."<init>":()V #24 = NameAndType #6:#7 // MODULE$:LSimple$; #25 = Fieldref #2.#24 // Simple$.MODULE$:LSimple$; #26 = Utf8 Yanne #27 = String #26 // Yanne #28 = Utf8 Code #29 = Utf8 LocalVariableTable #30 = Utf8 LineNumberTable #31 = Utf8 SourceFile #32 = Utf8 ScalaInlineInfo #33 = Utf8 Scala { public static final Simple$ MODULE$; flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL private final java.lang.String name; flags: ACC_PRIVATE, ACC_FINAL public static {}; flags: ACC_PUBLIC, ACC_STATIC Code: stack=1, locals=0, args_size=0 0: new #2 // class Simple$ 3: invokespecial #12 // Method "<init>":()V 6: return public java.lang.String name(); flags: ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: getfield #17 // Field name:Ljava/lang/String; 4: areturn LocalVariableTable: Start Length Slot Name Signature 0 5 0 this LSimple$; LineNumberTable: line 2: 0 public void main(java.lang.String[]); flags: ACC_PUBLIC Code: stack=0, locals=2, args_size=2 0: return LocalVariableTable: Start Length Slot Name Signature 0 1 0 this LSimple$; 0 1 1 args [Ljava/lang/String; LineNumberTable: line 3: 0 private Simple$(); flags: ACC_PRIVATE Code: stack=2, locals=1, args_size=1 0: aload_0 1: invokespecial #23 // Method java/lang/Object."<init>":()V 4: aload_0 5: putstatic #25 // Field MODULE$:LSimple$; 8: aload_0 9: ldc #27 // String Yanne 11: putfield #17 // Field name:Ljava/lang/String; 14: return LocalVariableTable: Start Length Slot Name Signature 0 15 0 this LSimple$; LineNumberTable: line 6: 0 line 2: 8 }
對應的val 類型屬性name在虛構類中變成了private final類型的,同時,在虛構類中也會生成同名的public函數。其實,這就是一個getter。
那,若是是var類型的屬性呢?
object Simple { var name ="Yanne" def main(args:Array[String]){ } }
javap -c -v -private Simple
Classfile /Users/Yanne/project/scala/deepscala/Simple.class Last modified 2016-5-13; size 827 bytes MD5 checksum 372cc57ba09d21cb6e4b7cbddd1e10d3 Compiled from "Simple.scala" public final class Simple SourceFile: "Simple.scala" RuntimeVisibleAnnotations: 0: #6(#7=s#8) ScalaSig: length = 0x3 05 00 00 minor version: 0 major version: 50 flags: ACC_PUBLIC, ACC_FINAL, ACC_SUPER Constant pool: #1 = Utf8 Simple #2 = Class #1 // Simple #3 = Utf8 java/lang/Object #4 = Class #3 // java/lang/Object #5 = Utf8 Simple.scala #6 = Utf8 Lscala/reflect/ScalaSignature; #7 = Utf8 bytes #8 = Utf8 Y:Q!\t\taaU5na2,'\"Aq*W;z}\ra!I!AB*j[BdWA1BD)\tQ\"AtGd-\t1I\=SKDQ!EI\taP5oSRtD#A\tQ9!C+!a.Y7f+1CA A\"BA\raM\4 m\tAA[1wC&Q'RN\4\t}9!CAAa.Y7f?*\"IA1BIG1A!8ji\"9QEHA1a=%c!1qeQ!\nY\tQA\1nKBQ!K)\nA!\1j]Re Y!\r!LCJ<7E ]AJ!a (/Y=E\"dBA3\tD\"Qe$WMZ;UR!a\r #9 = Utf8 main #10 = Utf8 ([Ljava/lang/String;)V #11 = Utf8 Simple$ #12 = Class #11 // Simple$ #13 = Utf8 MODULE$ #14 = Utf8 LSimple$; #15 = NameAndType #13:#14 // MODULE$:LSimple$; #16 = Fieldref #12.#15 // Simple$.MODULE$:LSimple$; #17 = NameAndType #9:#10 // main:([Ljava/lang/String;)V #18 = Methodref #12.#17 // Simple$.main:([Ljava/lang/String;)V #19 = Utf8 name_$eq #20 = Utf8 (Ljava/lang/String;)V #21 = NameAndType #19:#20 // name_$eq:(Ljava/lang/String;)V #22 = Methodref #12.#21 // Simple$.name_$eq:(Ljava/lang/String;)V #23 = Utf8 name #24 = Utf8 ()Ljava/lang/String; #25 = NameAndType #23:#24 // name:()Ljava/lang/String; #26 = Methodref #12.#25 // Simple$.name:()Ljava/lang/String; #27 = Utf8 Code #28 = Utf8 SourceFile #29 = Utf8 RuntimeVisibleAnnotations #30 = Utf8 ScalaSig { public static void main(java.lang.String[]); flags: ACC_PUBLIC, ACC_STATIC Code: stack=2, locals=1, args_size=1 0: getstatic #16 // Field Simple$.MODULE$:LSimple$; 3: aload_0 4: invokevirtual #18 // Method Simple$.main:([Ljava/lang/String;)V 7: return public static void name_$eq(java.lang.String); flags: ACC_PUBLIC, ACC_STATIC Code: stack=2, locals=1, args_size=1 0: getstatic #16 // Field Simple$.MODULE$:LSimple$; 3: aload_0 4: invokevirtual #22 // Method Simple$.name_$eq:(Ljava/lang/String;)V 7: return public static java.lang.String name(); flags: ACC_PUBLIC, ACC_STATIC Code: stack=1, locals=0, args_size=0 0: getstatic #16 // Field Simple$.MODULE$:LSimple$; 3: invokevirtual #26 // Method Simple$.name:()Ljava/lang/String; 6: areturn }
從上面的編譯結果來看,針對var類型屬性,會自動生成靜態的setter和getter。這個類裏面的生成規則是同樣的。那如今虛構類中的狀況是如何的呢?
javap -c -v -private Simple$
Classfile /Users/Yanne/project/scala/deepscala/Simple$.class Last modified 2016-5-13; size 781 bytes MD5 checksum 66580c4b3c9bb57066b03a759e69c8da Compiled from "Simple.scala" public final class Simple$ SourceFile: "Simple.scala" ScalaInlineInfo: length = 0x18 01 01 00 04 00 0A 00 09 01 00 16 00 17 01 00 0D 00 0F 01 00 13 00 14 01 Scala: length = 0x0 minor version: 0 major version: 50 flags: ACC_PUBLIC, ACC_FINAL, ACC_SUPER Constant pool: #1 = Utf8 Simple$ #2 = Class #1 // Simple$ #3 = Utf8 java/lang/Object #4 = Class #3 // java/lang/Object #5 = Utf8 Simple.scala #6 = Utf8 MODULE$ #7 = Utf8 LSimple$; #8 = Utf8 <clinit> #9 = Utf8 ()V #10 = Utf8 <init> #11 = NameAndType #10:#9 // "<init>":()V #12 = Methodref #2.#11 // Simple$."<init>":()V #13 = Utf8 name #14 = Utf8 Ljava/lang/String; #15 = Utf8 ()Ljava/lang/String; #16 = NameAndType #13:#14 // name:Ljava/lang/String; #17 = Fieldref #2.#16 // Simple$.name:Ljava/lang/String; #18 = Utf8 this #19 = Utf8 name_$eq #20 = Utf8 (Ljava/lang/String;)V #21 = Utf8 x$1 #22 = Utf8 main #23 = Utf8 ([Ljava/lang/String;)V #24 = Utf8 args #25 = Utf8 [Ljava/lang/String; #26 = Methodref #4.#11 // java/lang/Object."<init>":()V #27 = NameAndType #6:#7 // MODULE$:LSimple$; #28 = Fieldref #2.#27 // Simple$.MODULE$:LSimple$; #29 = Utf8 Yanne #30 = String #29 // Yanne #31 = Utf8 Code #32 = Utf8 LocalVariableTable #33 = Utf8 LineNumberTable #34 = Utf8 SourceFile #35 = Utf8 ScalaInlineInfo #36 = Utf8 Scala { public static final Simple$ MODULE$; flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL private java.lang.String name; flags: ACC_PRIVATE public static {}; flags: ACC_PUBLIC, ACC_STATIC Code: stack=1, locals=0, args_size=0 0: new #2 // class Simple$ 3: invokespecial #12 // Method "<init>":()V 6: return public java.lang.String name(); flags: ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: getfield #17 // Field name:Ljava/lang/String; 4: areturn LocalVariableTable: Start Length Slot Name Signature 0 5 0 this LSimple$; LineNumberTable: line 2: 0 public void name_$eq(java.lang.String); flags: ACC_PUBLIC Code: stack=2, locals=2, args_size=2 0: aload_0 1: aload_1 2: putfield #17 // Field name:Ljava/lang/String; 5: return LocalVariableTable: Start Length Slot Name Signature 0 6 0 this LSimple$; 0 6 1 x$1 Ljava/lang/String; LineNumberTable: line 2: 0 public void main(java.lang.String[]); flags: ACC_PUBLIC Code: stack=0, locals=2, args_size=2 0: return LocalVariableTable: Start Length Slot Name Signature 0 1 0 this LSimple$; 0 1 1 args [Ljava/lang/String; LineNumberTable: line 3: 0 private Simple$(); flags: ACC_PRIVATE Code: stack=2, locals=1, args_size=1 0: aload_0 1: invokespecial #26 // Method java/lang/Object."<init>":()V 4: aload_0 5: putstatic #28 // Field MODULE$:LSimple$; 8: aload_0 9: ldc #30 // String Yanne 11: putfield #17 // Field name:Ljava/lang/String; 14: return LocalVariableTable: Start Length Slot Name Signature 0 15 0 this LSimple$; LineNumberTable: line 6: 0 line 2: 8 }
對應的var類型屬性已經再也不是final的了,而是能夠改變的,同時,也有配套的getter和setter。可是名字不是和javabean裏面的使用習慣是一致的,那麼,咱們如今能不能用scala.beans.BeanProperty來註釋呢?
object Simple { @scala.beans.BeanProperty var name ="Yanne" def main(args:Array[String]){ } }
javap -c -v -private Simple
Classfile /Users/Yanne/project/scala/deepscala/Simple.class Last modified 2016-5-13; size 1035 bytes MD5 checksum 540b87e6d10abfde7cf477e0423c369f Compiled from "Simple.scala" public final class Simple SourceFile: "Simple.scala" RuntimeVisibleAnnotations: 0: #6(#7=s#8) ScalaSig: length = 0x3 05 00 00 minor version: 0 major version: 50 flags: ACC_PUBLIC, ACC_FINAL, ACC_SUPER Constant pool: #1 = Utf8 Simple #2 = Class #1 // Simple #3 = Utf8 java/lang/Object #4 = Class #3 // java/lang/Object #5 = Utf8 Simple.scala #6 = Utf8 Lscala/reflect/ScalaSignature; #7 = Utf8 bytes #8 = Utf8 ;Q!\t\taaU5na2,'\"Aq*W;z}\ra!I!AB*j[BdWA1BD)\tQ\"AtGd-\t1I\=SKDQ!EI\taP5oSRtD#A\tQ9!C+!a.Y7f+1CA A\"BA\raM\4 m\tAA[1wC&Q'RN\4\t}9!CAAa.Y7f?*\"IA1BIG1A!8ji\"9QEHA1a=%c!1qeQ!\nY\tQA\1nKB#AJ)jS\"A 1b!2fC:B,1U-8Qe>XM;zt\"29W\r(b[$Ag!\tg$h*Y7f)\t\tSC&e\t \t ]:A\t5 N CeBQAAm\nA!:hgB1 \nub!!B!seCA C\tY)B1K]3eKL!!H\" c #9 = Utf8 main #10 = Utf8 ([Ljava/lang/String;)V #11 = Utf8 Simple$ #12 = Class #11 // Simple$ #13 = Utf8 MODULE$ #14 = Utf8 LSimple$; #15 = NameAndType #13:#14 // MODULE$:LSimple$; #16 = Fieldref #12.#15 // Simple$.MODULE$:LSimple$; #17 = NameAndType #9:#10 // main:([Ljava/lang/String;)V #18 = Methodref #12.#17 // Simple$.main:([Ljava/lang/String;)V #19 = Utf8 setName #20 = Utf8 (Ljava/lang/String;)V #21 = NameAndType #19:#20 // setName:(Ljava/lang/String;)V #22 = Methodref #12.#21 // Simple$.setName:(Ljava/lang/String;)V #23 = Utf8 getName #24 = Utf8 ()Ljava/lang/String; #25 = NameAndType #23:#24 // getName:()Ljava/lang/String; #26 = Methodref #12.#25 // Simple$.getName:()Ljava/lang/String; #27 = Utf8 name_$eq #28 = NameAndType #27:#20 // name_$eq:(Ljava/lang/String;)V #29 = Methodref #12.#28 // Simple$.name_$eq:(Ljava/lang/String;)V #30 = Utf8 name #31 = NameAndType #30:#24 // name:()Ljava/lang/String; #32 = Methodref #12.#31 // Simple$.name:()Ljava/lang/String; #33 = Utf8 Code #34 = Utf8 SourceFile #35 = Utf8 RuntimeVisibleAnnotations #36 = Utf8 ScalaSig { public static void main(java.lang.String[]); flags: ACC_PUBLIC, ACC_STATIC Code: stack=2, locals=1, args_size=1 0: getstatic #16 // Field Simple$.MODULE$:LSimple$; 3: aload_0 4: invokevirtual #18 // Method Simple$.main:([Ljava/lang/String;)V 7: return public static void setName(java.lang.String); flags: ACC_PUBLIC, ACC_STATIC Code: stack=2, locals=1, args_size=1 0: getstatic #16 // Field Simple$.MODULE$:LSimple$; 3: aload_0 4: invokevirtual #22 // Method Simple$.setName:(Ljava/lang/String;)V 7: return public static java.lang.String getName(); flags: ACC_PUBLIC, ACC_STATIC Code: stack=1, locals=0, args_size=0 0: getstatic #16 // Field Simple$.MODULE$:LSimple$; 3: invokevirtual #26 // Method Simple$.getName:()Ljava/lang/String; 6: areturn public static void name_$eq(java.lang.String); flags: ACC_PUBLIC, ACC_STATIC Code: stack=2, locals=1, args_size=1 0: getstatic #16 // Field Simple$.MODULE$:LSimple$; 3: aload_0 4: invokevirtual #29 // Method Simple$.name_$eq:(Ljava/lang/String;)V 7: return public static java.lang.String name(); flags: ACC_PUBLIC, ACC_STATIC Code: stack=1, locals=0, args_size=0 0: getstatic #16 // Field Simple$.MODULE$:LSimple$; 3: invokevirtual #32 // Method Simple$.name:()Ljava/lang/String; 6: areturn }
從上面編譯的結果來看,咱們是能夠用scala.beans.BeanProperty來註釋的。
其實,上面的object都是孤立對象,由於沒有和他同名的class,孤立對象的規則是,會生成同名的class和一個虛構的class,同名的class裏面只有靜態屬性和靜態方法,而虛構類纔是真正的的幹活地方。
那麼,若是在同一個文件,有一個和object同名的class 又會怎樣呢?
object Simple { @scala.beans.BeanProperty var name ="Yanne" def main(args:Array[String]){ } } class Simple { val age =10 var address= "KM" def say()={println("Hello")} }
一樣的,當你scalac Simple.scala 的時候,也會生成Simple.class 和Simple$.class 兩個class文件。咱們先來看看Simple$.class 和之前有什麼不一樣。
javap -c -v -private Simple$
Classfile /Users/Yanne/project/scala/deepscala/Simple$.class Last modified 2016-5-13; size 954 bytes MD5 checksum 77245177287d300dde1fa9be95f90d8a Compiled from "Simple.scala" public final class Simple$ SourceFile: "Simple.scala" ScalaInlineInfo: length = 0x22 01 01 00 06 00 0A 00 09 01 00 1B 00 0F 01 00 17 00 18 01 00 0D 00 0F 01 00 13 00 14 01 00 16 00 14 01 Scala: length = 0x0 minor version: 0 major version: 50 flags: ACC_PUBLIC, ACC_FINAL, ACC_SUPER Constant pool: #1 = Utf8 Simple$ #2 = Class #1 // Simple$ #3 = Utf8 java/lang/Object #4 = Class #3 // java/lang/Object #5 = Utf8 Simple.scala #6 = Utf8 MODULE$ #7 = Utf8 LSimple$; #8 = Utf8 <clinit> #9 = Utf8 ()V #10 = Utf8 <init> #11 = NameAndType #10:#9 // "<init>":()V #12 = Methodref #2.#11 // Simple$."<init>":()V #13 = Utf8 name #14 = Utf8 Ljava/lang/String; #15 = Utf8 ()Ljava/lang/String; #16 = NameAndType #13:#14 // name:Ljava/lang/String; #17 = Fieldref #2.#16 // Simple$.name:Ljava/lang/String; #18 = Utf8 this #19 = Utf8 name_$eq #20 = Utf8 (Ljava/lang/String;)V #21 = Utf8 x$1 #22 = Utf8 setName #23 = Utf8 main #24 = Utf8 ([Ljava/lang/String;)V #25 = Utf8 args #26 = Utf8 [Ljava/lang/String; #27 = Utf8 getName #28 = NameAndType #13:#15 // name:()Ljava/lang/String; #29 = Methodref #2.#28 // Simple$.name:()Ljava/lang/String; #30 = Methodref #4.#11 // java/lang/Object."<init>":()V #31 = NameAndType #6:#7 // MODULE$:LSimple$; #32 = Fieldref #2.#31 // Simple$.MODULE$:LSimple$; #33 = Utf8 Yanne #34 = String #33 // Yanne #35 = Utf8 Code #36 = Utf8 LocalVariableTable #37 = Utf8 LineNumberTable #38 = Utf8 SourceFile #39 = Utf8 ScalaInlineInfo #40 = Utf8 Scala { public static final Simple$ MODULE$; flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL private java.lang.String name; flags: ACC_PRIVATE public static {}; flags: ACC_PUBLIC, ACC_STATIC Code: stack=1, locals=0, args_size=0 0: new #2 // class Simple$ 3: invokespecial #12 // Method "<init>":()V 6: return public java.lang.String name(); flags: ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: getfield #17 // Field name:Ljava/lang/String; 4: areturn LocalVariableTable: Start Length Slot Name Signature 0 5 0 this LSimple$; LineNumberTable: line 2: 0 public void name_$eq(java.lang.String); flags: ACC_PUBLIC Code: stack=2, locals=2, args_size=2 0: aload_0 1: aload_1 2: putfield #17 // Field name:Ljava/lang/String; 5: return LocalVariableTable: Start Length Slot Name Signature 0 6 0 this LSimple$; 0 6 1 x$1 Ljava/lang/String; LineNumberTable: line 2: 0 public void setName(java.lang.String); flags: ACC_PUBLIC Code: stack=2, locals=2, args_size=2 0: aload_0 1: aload_1 2: putfield #17 // Field name:Ljava/lang/String; 5: return LocalVariableTable: Start Length Slot Name Signature 0 6 0 this LSimple$; 0 6 1 x$1 Ljava/lang/String; LineNumberTable: line 2: 0 public void main(java.lang.String[]); flags: ACC_PUBLIC Code: stack=0, locals=2, args_size=2 0: return LocalVariableTable: Start Length Slot Name Signature 0 1 0 this LSimple$; 0 1 1 args [Ljava/lang/String; LineNumberTable: line 3: 0 public java.lang.String getName(); flags: ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: invokevirtual #29 // Method name:()Ljava/lang/String; 4: areturn LocalVariableTable: Start Length Slot Name Signature 0 5 0 this LSimple$; LineNumberTable: line 2: 0 private Simple$(); flags: ACC_PRIVATE Code: stack=2, locals=1, args_size=1 0: aload_0 1: invokespecial #30 // Method java/lang/Object."<init>":()V 4: aload_0 5: putstatic #32 // Field MODULE$:LSimple$; 8: aload_0 9: ldc #34 // String Yanne 11: putfield #17 // Field name:Ljava/lang/String; 14: return LocalVariableTable: Start Length Slot Name Signature 0 15 0 this LSimple$; LineNumberTable: line 9: 0 line 2: 8 }
咱們雖然在同名的class下增長了val,var類型屬性以及方法,可是,虛構類(Simple$)是徹底沒有反應的,也就是說,虛構類裏面永遠是對object的反應,而對class是無動於衷的。
咱們如今來看看Simple.class
javap -c -v -private Simple
Classfile /Users/Yanne/project/scala/deepscala/Simple.class Last modified 2016-5-13; size 1905 bytes MD5 checksum d9961f1b0349ef14e9754696f3e291ca Compiled from "Simple.scala" public class Simple SourceFile: "Simple.scala" RuntimeVisibleAnnotations: 0: #6(#7=s#8) ScalaInlineInfo: length = 0x1D 01 00 00 05 00 3B 00 2F 00 00 23 00 18 00 00 2C 00 14 00 00 21 00 25 00 00 2E 00 2F 00 ScalaSig: length = 0x3 05 00 00 minor version: 0 major version: 50 flags: ACC_PUBLIC, ACC_SUPER Constant pool: #1 = Utf8 Simple #2 = Class #1 // Simple #3 = Utf8 java/lang/Object #4 = Class #3 // java/lang/Object #5 = Utf8 Simple.scala #6 = Utf8 Lscala/reflect/ScalaSignature; #7 = Utf8 bytes #8 = Utf8 q;Q!\t\taaU5na2,'\"Aq*W;z}\ra!I!AB*j[BdWA1BD)\tQ\"AtGd-\t1I\=SKDQ!EI\taP5oSRtD#A\tQ9!C+!a.Y7f+1CA A\"BA\raM\4 m\tAA[1wC&Q'RN\4\t}9!CAAa.Y7f?*\"IA1BIG1A!8ji\"9QEHA1a=%c!1qeQ!\nY\tQA\1nKB#AJ)jS\"A 1b!2fC:B,1U-8Qe>XM;zt\"29W\r(b[$Ag!\tg$h*Y7f)\t\tSC&e\t \t ]:A\t5 N CeBQAAm\nA!:hgB1 \nub!!B!seCA C\tY)B1K]3eKL!!H\" ca"\t E!EA$!\"A#\t)#%!CmZ31\"aC'\n9c!aA%oi\"1 Q\n1 A!Y4fA!9! a\n)aB1eIJ,7)\r\"V-\tG\r:fgN|F%Z92bBT\rA1 $GM]3tgBQA#m 1a]1z)\t #9 = Utf8 main #10 = Utf8 ([Ljava/lang/String;)V #11 = Utf8 Simple$ #12 = Class #11 // Simple$ #13 = Utf8 MODULE$ #14 = Utf8 LSimple$; #15 = NameAndType #13:#14 // MODULE$:LSimple$; #16 = Fieldref #12.#15 // Simple$.MODULE$:LSimple$; #17 = NameAndType #9:#10 // main:([Ljava/lang/String;)V #18 = Methodref #12.#17 // Simple$.main:([Ljava/lang/String;)V #19 = Utf8 setName #20 = Utf8 (Ljava/lang/String;)V #21 = NameAndType #19:#20 // setName:(Ljava/lang/String;)V #22 = Methodref #12.#21 // Simple$.setName:(Ljava/lang/String;)V #23 = Utf8 getName #24 = Utf8 ()Ljava/lang/String; #25 = NameAndType #23:#24 // getName:()Ljava/lang/String; #26 = Methodref #12.#25 // Simple$.getName:()Ljava/lang/String; #27 = Utf8 name_$eq #28 = NameAndType #27:#20 // name_$eq:(Ljava/lang/String;)V #29 = Methodref #12.#28 // Simple$.name_$eq:(Ljava/lang/String;)V #30 = Utf8 name #31 = NameAndType #30:#24 // name:()Ljava/lang/String; #32 = Methodref #12.#31 // Simple$.name:()Ljava/lang/String; #33 = Utf8 age #34 = Utf8 I #35 = Utf8 address #36 = Utf8 Ljava/lang/String; #37 = Utf8 ()I #38 = NameAndType #33:#34 // age:I #39 = Fieldref #2.#38 // Simple.age:I #40 = Utf8 this #41 = Utf8 LSimple; #42 = NameAndType #35:#36 // address:Ljava/lang/String; #43 = Fieldref #2.#42 // Simple.address:Ljava/lang/String; #44 = Utf8 address_$eq #45 = Utf8 x$1 #46 = Utf8 say #47 = Utf8 ()V #48 = Utf8 scala/Predef$ #49 = Class #48 // scala/Predef$ #50 = Utf8 Lscala/Predef$; #51 = NameAndType #13:#50 // MODULE$:Lscala/Predef$; #52 = Fieldref #49.#51 // scala/Predef$.MODULE$:Lscala/Predef$; #53 = Utf8 Hello #54 = String #53 // Hello #55 = Utf8 println #56 = Utf8 (Ljava/lang/Object;)V #57 = NameAndType #55:#56 // println:(Ljava/lang/Object;)V #58 = Methodref #49.#57 // scala/Predef$.println:(Ljava/lang/Object;)V #59 = Utf8 <init> #60 = NameAndType #59:#47 // "<init>":()V #61 = Methodref #4.#60 // java/lang/Object."<init>":()V #62 = Utf8 KM #63 = String #62 // KM #64 = Utf8 Code #65 = Utf8 LocalVariableTable #66 = Utf8 LineNumberTable #67 = Utf8 SourceFile #68 = Utf8 RuntimeVisibleAnnotations #69 = Utf8 ScalaInlineInfo #70 = Utf8 ScalaSig { private final int age; flags: ACC_PRIVATE, ACC_FINAL private java.lang.String address; flags: ACC_PRIVATE public static void main(java.lang.String[]); flags: ACC_PUBLIC, ACC_STATIC Code: stack=2, locals=1, args_size=1 0: getstatic #16 // Field Simple$.MODULE$:LSimple$; 3: aload_0 4: invokevirtual #18 // Method Simple$.main:([Ljava/lang/String;)V 7: return public static void setName(java.lang.String); flags: ACC_PUBLIC, ACC_STATIC Code: stack=2, locals=1, args_size=1 0: getstatic #16 // Field Simple$.MODULE$:LSimple$; 3: aload_0 4: invokevirtual #22 // Method Simple$.setName:(Ljava/lang/String;)V 7: return public static java.lang.String getName(); flags: ACC_PUBLIC, ACC_STATIC Code: stack=1, locals=0, args_size=0 0: getstatic #16 // Field Simple$.MODULE$:LSimple$; 3: invokevirtual #26 // Method Simple$.getName:()Ljava/lang/String; 6: areturn public static void name_$eq(java.lang.String); flags: ACC_PUBLIC, ACC_STATIC Code: stack=2, locals=1, args_size=1 0: getstatic #16 // Field Simple$.MODULE$:LSimple$; 3: aload_0 4: invokevirtual #29 // Method Simple$.name_$eq:(Ljava/lang/String;)V 7: return public static java.lang.String name(); flags: ACC_PUBLIC, ACC_STATIC Code: stack=1, locals=0, args_size=0 0: getstatic #16 // Field Simple$.MODULE$:LSimple$; 3: invokevirtual #32 // Method Simple$.name:()Ljava/lang/String; 6: areturn public int age(); flags: ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: getfield #39 // Field age:I 4: ireturn LocalVariableTable: Start Length Slot Name Signature 0 5 0 this LSimple; LineNumberTable: line 10: 0 public java.lang.String address(); flags: ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: getfield #43 // Field address:Ljava/lang/String; 4: areturn LocalVariableTable: Start Length Slot Name Signature 0 5 0 this LSimple; LineNumberTable: line 11: 0 public void address_$eq(java.lang.String); flags: ACC_PUBLIC Code: stack=2, locals=2, args_size=2 0: aload_0 1: aload_1 2: putfield #43 // Field address:Ljava/lang/String; 5: return LocalVariableTable: Start Length Slot Name Signature 0 6 0 this LSimple; 0 6 1 x$1 Ljava/lang/String; LineNumberTable: line 11: 0 public void say(); flags: ACC_PUBLIC Code: stack=2, locals=1, args_size=1 0: getstatic #52 // Field scala/Predef$.MODULE$:Lscala/Predef$; 3: ldc #54 // String Hello 5: invokevirtual #58 // Method scala/Predef$.println:(Ljava/lang/Object;)V 8: return LocalVariableTable: Start Length Slot Name Signature 0 9 0 this LSimple; LineNumberTable: line 12: 0 public Simple(); flags: ACC_PUBLIC Code: stack=2, locals=1, args_size=1 0: aload_0 1: invokespecial #61 // Method java/lang/Object."<init>":()V 4: aload_0 5: bipush 10 7: putfield #39 // Field age:I 10: aload_0 11: ldc #63 // String KM 13: putfield #43 // Field address:Ljava/lang/String; 16: return LocalVariableTable: Start Length Slot Name Signature 0 17 0 this LSimple; LineNumberTable: line 13: 0 line 10: 4 line 11: 10 }
從上面看到,在class中定義的全部屬性所有體如今了這個裏面。
到這裏,咱們基本完成了對象的學習了,其實對應於孤立對象,咱們如今的同名的object和class出如今同一個文件中,那麼這種狀況就是伴生,obejct就是class的伴生對象,class是object的伴生類。
**對象** **孤立對象** **虛構類** **伴生對象** **伴生類**
從上面的伴生對象來看,實際上,伴生對象不是單列的,只有孤立對象是單列的,由於孤立對象的全部屬性(Field和method)都是靜態的,那麼,有沒有辦法讓伴生對象也能夠是單列的呢?
第一種方法固然只用孤立對象啦,不要再用伴生類。可是這不太現實呀,伴生類不少狀況下是必需要存在的,那怎麼辦呢?
咱們看看下面的例子:
object Simple { val sm=new Simple @scala.beans.BeanProperty var name ="Yanne" def main(args:Array[String]){ } } class Simple private { val age =10 var address= "KM" def say()={println("Hello")} }
上面的用法是將伴生類的構造器變成私有的了。而且在伴生對象中生成了一個伴生對象的實例。
object Simple { val sm=new Simple @scala.beans.BeanProperty var name ="Yanne" def main(args:Array[String]){ } def apply()={ new Simple } } class Simple { val age =10 var address= "KM" def say()={println("Hello")} }
這樣子的話,咱們就可使用Simple() 這種實例化一個Simple對象了,這是爲啥呢? 實際上你能夠把這個當作是()的重載,他背後就是調用了apply方法。