Scala--樣例類(case)詳解


概述:

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

1.實現了apply方法,意味着你不需要使用new關鍵字就能創建該類對象
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中抽取器的實現和模式匹配的關鍵方法。
scala> p match { case People(x,y) => println(x,y) }
(mobin,22)

 

3.實現了類構造參數的getter方法(構造參數默認被聲明為val),但是當你構造參數是聲明為var類型的,它將幫你實現setter和getter方法(不建議將構造參數聲明為var)

 
構造參數為val的情況(默認):
scala> p.name
res0: String = mobin
 
scala> p.name = "mobin1" //報錯,因為構造參數被聲明為val所以並沒有幫你實現setter方法
<console>:10: error: reassignment to val
p.name = "mobin1"
 
構造參數為var的情況:
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
case class Person(name: String,age : Int)

  

通過終端中編譯該文件(scalac Person.scala)后生成兩個class文件,Person.class和Person$.class
 
接下來再通過javap Person命令反編譯Person.class,結果結果如下:
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
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關鍵字將類定義為普通類后反編譯的結果
class Person(var name : String,var age : Int) //將參數聲明為var

  

反編譯的結果如下:
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本就旨在創建的是不可變數據,所以在使用模式匹配時顯得極為容易
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM