scala之case class 和case object


首先我們我們對case class 和case object類型對象進行反編譯

首先來編譯 case class,有如下編譯內容:

case class Person(age:Int,name:String)

它會產生兩個文件如下:

Person.class的編譯內容如下:

import scala.Function1; import scala.Option; import scala.Product; import scala.Product.class; import scala.Serializable; import scala.Tuple2; import scala.collection.Iterator; import scala.reflect.ScalaSignature; import scala.runtime.BoxesRunTime; import scala.runtime.ScalaRunTime.; import scala.runtime.Statics; @ScalaSignature(bytes="\6\1\5-b\1B\1\3\1\22\17a\1U3sg>t'\"A\2\2\15q*W\14\29;z}\r\11\3\2\1\7\25=\1\"a\2\6\14\3!Q\17!C\1\6g\14\fG.Y\5\3\23!\17a!\178z%\224\7CA\4\14\19\tq\1BA\4Qe>$Wo\25;\17\5\29\1\18BA\t\t\51\25VM]5bY&T\24M\257f\17!\25\2A!f\1\n\3!\18aA1hKV\tQ\3\5\2\b-%\17q\3\3\2\4\19:$\b\2C\r\1\5#\5\11\17B\11\2\t\5<W\r\t\5\t7\1\17)\26!C\19\5!a.Y7f+\5i\2C\1\16\"\29\t9q$\3\2!\17\51\1K]3eK\26L!AI\18\3\rM#(/\278h\21\t\1\3\2\3\5&\1\tE\t\21!\3\30\3\21q\23-\\3!\17\219\3\1\"\1)\3\25a\20N\\5u}Q\25\17f\11\23\17\5)\2Q\"\1\2\t\11M1\3\25A\11\t\11m1\3\25A\15\t\159\2\17\17!C\1_\5!1m\289z)\rI\3'\r\5\b'5\2\n\171\1\22\17\29YR\6%AA\2uAqa\r\1\18\2\19\5A'\1\bd_BLH\5Z3gCVdG\15J\25\22\3UR#!\6\28,\3]\2\"\1O\31\14\3eR!AO\30\2\19Ut7\r[3dW\22$'B\1\31\t\3)\tgN\\8uCRLwN\\\5\3}e\18\17#\308dQ\22\287.\263WCJL\23M\\2f\17\29\1\5!%A\5\2\5\11abY8qs\18\"WMZ1vYR$#'F\1CU\tib\7C\4E\1\5\5I\17I#\2\27A\20x\14Z;diB\19XMZ5y+\51\5CA$M\27\5A%BA%K\3\17a\23M\\4\11\3-\11AA[1wC&\17!\5\19\5\b\29\2\t\t\17\"\1\21\31\1(o\283vGR\f%/\27;z\17\29\1\6!!A\5\2E\11a\2\29:pIV\28G/\187f[\22tG\15\6\2S+B\17qaU\5\3)\"\171!\178z\17\291v*!AA\2U\t1\1\31\192\17\29A\6!!A\5Be\11q\2\29:pIV\28G/\19;fe\6$xN]\11\25B\251L\24*\14\3qS!!\24\5\2\21\r|G\14\\3di&|g.\3\2`9\nA\17\n^3sCR|'\15C\4b\1\5\5I\17\12\2\17\r\fg.R9vC2$\"a\254\17\5\29!\23BA3\t\5\29\17un\287fC:DqA\221\2\2\3\7!\11C\4i\1\5\5I\17I5\2\17!\f7\15[\"pI\22$\18!\6\5\bW\2\t\t\17\"\17m\3!!xn\21;sS:<G#\1$\t\159\4\17\17!C!_\61Q-];bYN$\"a\259\t\15Yk\23\17!a\1%\309!OAA\1\18\3\25\24A\2)feN|g\14\5\2+i\269\17AAA\1\18\3)8c\1;w\31A)qO_\11\30S5\t\1P\3\2z\17\59!/\308uS6,\23BA>y\5E\t%m\29;sC\14$h)\308di&|gN\r\5\6OQ$\t! \11\2g\"91\14^A\1\n\11b\7\"CA\1i\6\5I\17QA\2\3\21\t\7\15\297z)\21I\19QAA\4\17\21\25r\161\1\22\17\21Yr\161\1\30\17%\tY\1^A\1\n\3\11i!A\4v]\6\4\b\15\\=\21\t\5=\171\4\t\6\15\5E\17QC\5\4\3'A!AB(qi&|g\14E\3\b\3/)R$C\2\2\26!\17a\1V;qY\22\20\4\"CA\15\3\19\t\t\171\1*\3\rAH\5\r\5\n\3C!\24\17!C\5\3G\t1B]3bIJ+7o\287wKR\17\17Q\5\t\4\15\6\29\18bAA\21\17\n1qJ\256fGR\4") public class Person implements Product, Serializable { private final int age; private final String name; public static Option<Tuple2<Object, String>> unapply(Person paramPerson) { return Person..MODULE$.unapply(paramPerson); } public static Person apply(int paramInt, String paramString) { return Person..MODULE$.apply(paramInt, paramString); } public static Function1<Tuple2<Object, String>, Person> tupled() { return Person..MODULE$.tupled(); } public static Function1<Object, Function1<String, Person>> curried() { return Person..MODULE$.curried(); } public int age(){return this.age; } public String name() { return this.name; } public Person copy(int age, String name) { return new Person(age, name); } public int copy$default$1() { return age(); } public String copy$default$2() { return name(); } public String productPrefix() { return "Person"; } public int productArity() { return 2; } public Object productElement(int x$1) { int i = x$1; switch (i) { default: throw new IndexOutOfBoundsException(BoxesRunTime.boxToInteger(x$1).toString()); case 1: case 0: } return BoxesRunTime.boxToInteger(age()); } public Iterator<Object> productIterator() { return ScalaRunTime..MODULE$.typedProductIterator(this); } public boolean canEqual(Object x$1) { return x$1 instanceof Person; } public int hashCode() { int i = -889275714; i = Statics.mix(i, age()); i = Statics.mix(i, Statics.anyHash(name())); return Statics.finalizeHash(i, 2); } public String toString() { return ScalaRunTime..MODULE$._toString(this); } public boolean equals(Object x$1) { int i; if (this == x$1) break label92; Object localObject = x$1; if (localObject instanceof Person) i = 1; else i = 0; if (i == 0) break label96; Person localPerson = (Person)x$1; if (age() != localPerson.age()) break label88; str = localPerson.name(); String tmp54_44 = name(); if (tmp54_44 != null) break label67; tmp54_44; if (str == null) break label75; label67: label75: label88: label92: label96: break label88: } public Person(int age, String name) { Product.class.$init$(this); } }

Person$.class的編譯內容如下:

import scala.Option; import scala.Serializable; import scala.Some; import scala.Tuple2; import scala.runtime.AbstractFunction2; import scala.runtime.BoxesRunTime; public final class  extends AbstractFunction2<Object, String, Person> implements Serializable { public static final MODULE$; static { new (); } public final String toString() { return "Person"; } public Person apply(, String name) { return new Person(age, name); } public Option<Tuple2<Object, String>> unapply() { return new Some(new Tuple2(BoxesRunTime.boxToInteger(x$0.age()), x$0.name())); } private Object readResolve() { return MODULE$; } private () { MODULE$ = this; } }

分析:
1、case 類在編譯的時候會自動增加一個 單列對象(single object)。

2、產生了一個apply的方法,那么我們可以直接把對象當作方法來用,比如 Person(12,Tom),就代表已經創建一個Person的對象,同時調用了這個對象的apply方法

3、產生了一個upapply的方法,也就是說在模式匹配的時候可以用case class Person來作為 age和name的提取器

4、繼承了Product和Serializable(implements Product, Serializable),也就是說已經序列化和可以應用Product的方法

5、age和name字段都是由final 修飾,也就是說是不可改變的,那么用scala的語言來闡述,那么就是 case class 的參數默認是  immutable類型的。

6、也包含了toString,hashCode,copy,equals方法。

我們再對case object person進行編譯

case object Person

結果如下:

 Person.class的編譯內容

import scala.Product; import scala.Product.class; import scala.Serializable; import scala.collection.Iterator; import scala.runtime.BoxesRunTime; import scala.runtime.ScalaRunTime.; public final class implements Product, Serializable { public static final MODULE$; static { new (); } public String productPrefix() { return "Person"; } public int productArity() { return 0; } public Object productElement() { int i = x$1; throw new IndexOutOfBoundsException(BoxesRunTime.boxToInteger(x$1).toString()); } public Iterator<Object> productIterator() { return ScalaRunTime..MODULE$.typedProductIterator(this); } public boolean canEqual() { return x$1 instanceof ; } public int hashCode() { return -1907849355; } public String toString() { return "Person"; } private Object readResolve() { return MODULE$; } private () { MODULE$ = this; Product.class.$init$(this); } }

Person$.class的編譯內容

import scala.Product; import scala.Product.class; import scala.Serializable; import scala.collection.Iterator; import scala.runtime.BoxesRunTime; import scala.runtime.ScalaRunTime.; public final class implements Product, Serializable { public static final MODULE$; static { new (); } public String productPrefix() { return "Person"; } public int productArity() { return 0; } public Object productElement() { int i = x$1; throw new IndexOutOfBoundsException(BoxesRunTime.boxToInteger(x$1).toString()); } public Iterator<Object> productIterator() { return ScalaRunTime..MODULE$.typedProductIterator(this); } public boolean canEqual() { return x$1 instanceof ; } public int hashCode() { return -1907849355; } public String toString() { return "Person"; } private Object readResolve() { return MODULE$; } private () { MODULE$ = this; Product.class.$init$(this); } }

分析
1、case object Person相比於case class Person(age:Int,name:String)缺少了apply、unapply方法,因為case object

是沒有參數輸入的,所以對於apply 和unapply的方法也自然失去。

2、因為class 和 object 在編譯的時候,object是只有一個編譯文件,而當兩者加上case之后發現兩者都是有2個編譯文件,也就是說case object 不在像object那樣僅僅是一個單列對象,而是有像類(class)一樣的特性。

3、都有toString,hashCode,copy,equals方法和繼承了Product和Serializable(implements Product, Serializable)

因為前面是case class Person(age:Int,name:String)和case object Person,因為class和object特征導致前者有參數,而后者無參數。而導致一些本質上的區別,下面再來編譯一下 case class Person,此刻是不帶參數的。發現和

case object Person 編譯的結果一模一樣。那么此刻是否認為case object 這個修飾這個是多余的。

從功能上來說是yes,

我們可以看看Mark Lewis,對此的闡述[2]

Functionally, the difference is the same as between a class and an object. The former creates a blueprint for making objects and the latter defines a singleton object in the scope in which it is declared. In both situations, adding the "case" keyword causes some syntactic sugar to be included. Less of that is needed for the objects than the classes. Starting with Scala 2.10, you should always use case objects instead of case classes with no arguments. The primary use case here is that you have values you want to pattern match on and some of those need arguments and others don't. The ones that don't take arguments should be declared as case objects while the ones that do should be case classes. This makes sense given that you really don't need multiple instances of an immutable type where the instances would all have identical values.

可以這么總結一句話,當Person有參數的時候,用case class ,當Person沒有參數的時候那么用case object。這一樣意義在於區分 有參和無參

總結

1、case 關鍵詞只用來修飾  class 和object,也就是說只有case class 和case object的存在 ,

而沒有case trait 或者class **這一說

2、case object /class A 這個A 是經過序列化,而且繼承了Product特性同時有toString,hashCode,copy,equals方法

3、case class 經常可以用於解析和提取

4、有參用case class ,無參用case object


免責聲明!

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



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