1. 程式人生 > >Scala樣例類詳細解釋

Scala樣例類詳細解釋



case類在模式匹配和actor中經常使用到,當一個類被定義成為case類後,Scala會自動幫你建立一個伴生物件並幫你實現了一系列方法且帶來了不少好處,如下:

1.實現了apply方法,意味著你不需要使用new關鍵字就能建立該類物件 ?
1 2 3 4 5 scala> case class People(name:String,age:Int) defined class People scala> val p = People("mobin",22) //省略了new關鍵字 p: People = People(mobin,22)
2.實現了unapply方法,可以通過模式匹配來獲取類屬性,是Scala中抽取器的實現和模式匹配的關鍵方法。
?
1 2 scala> p match { case People(x,y) => println(x,y) } (mobin,22)

3.實現了類構造引數的getter方法(構造引數預設被宣告為val),但是當你構造引數是宣告為var型別的,它將幫你實現setter和getter方法(不建議將構造引數宣告為var)

構造引數為val的情況(預設): ?
1 2 3 4 5 6 scala> p.name res0: String = mobin scala> p.name = "mobin1" //報錯,因為構造引數被宣告為val所以並沒有幫你實現setter方法
<console>:10: error: reassignment to val p.name = "mobin1"
構造引數為var的情況: ?
1 2 3 4 5 6 7 8 9 10 11 scala> case class People(var name:String) //引數被宣告為var defined class People scala> val p = People("mobin") p: People = People(mobin) scala> p.name = "mobin2" p.name: String = mobin2
scala> p.name res1: String = mobin2 //修改成功,並沒有報錯
4.還預設幫你實現了toString,equals,copy和hashCode等方法 詳述: 我們再通過反編譯來看看當你定義一個case類時編譯器是怎麼做的: 同樣定義一個簡單的case類: Person.scala ?
1 case class Person(name: String,age : Int)
通過終端中編譯該檔案(scalac Person.scala)後生成兩個class檔案,Person.class和Person$.class 接下來再通過javap Person命令反編譯Person.class,結果結果如下: ?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 Compiled from "Person.scala" public class com.mobin.scala.Person implements scala.Product,scala.Serializable { public static scala.Function1<scala.Tuple2<java.lang.String, java.lang.Object>, com.mobin.scala.Person> tupled(); public static scala.Function1<java.lang.String, scala.Function1<java.lang.Object, com.mobin.scala.Person>> curried(); public java.lang.String name(); public int age(); public com.mobin.scala.Person copy(java.lang.String, int); public java.lang.String copy$default$1(); public int copy$default$2(); public java.lang.String productPrefix(); public int productArity(); public java.lang.Object productElement(int); public scala.collection.Iterator<java.lang.Object> productIterator(); public boolean canEqual(java.lang.Object); public int hashCode(); public java.lang.String toString(); public boolean equals(java.lang.Object); public com.mobin.scala.Person(java.lang.String, int); }
再反編譯Person$.class ?
1 2 3 4 5 6 7 8 9 Compiled from "Person.scala" public final class com.mobin.scala.Person$ extends scala.runtime.AbstractFunction2<java.lang.String, java.lang.Object, com.mobin.scala.Person> implements scala.Serializable { public static final com.mobin.scala.Person$ MODULE$; public static {}; public final java.lang.String toString(); public com.mobin.scala.Person apply(java.lang.String, int); public scala.Option<scala.Tuple2<java.lang.String, java.lang.Object>> unapply(com.mobin.scala.Person); public java.lang.Object apply(java.lang.Object, java.lang.Object); }
通過反編譯以上兩個class檔案可以知道,當你將一個類定義為case類後,編譯器就自動幫你實現了一系列方法。 我們再來對比下去掉case關鍵字將類定義為普通類後反編譯的結果 ?
1 class Person(var name : String,var age : Int) //將引數宣告為var
反編譯的結果如下: ?
1 2 3 4 5 6 7 8 Compiled from "Person.scala" public class com.mobin.scala.Person { public java.lang.String name(); public void name_$eq(java.lang.String); public int age(); public void age_$eq(int); public com.mobin.scala.Person(java.lang.String, int); }
比較之下case類比普通的類多了不少的方法,所以當你不需要這些額外的方法時你就可以將類定義為普通的類,但是你又不想通過new關鍵字來建立例項,你可以在普通類中實現apply方法達到此目的。 因為case本就旨在建立的是不可變資料,所以在使用模式匹配時顯得極為容易