@云南犀鸟科技有限公司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方法。