Scala中單例類型及其使用場景

在Scala中,任何對象(包括單例對象和非單例對象)都存在單例類型,每個單例類型只有唯一的一個實例。

單例對象:

scala> object singletonObj // 定義單例對象
defined object singletonObj 
scala> import scala.reflect.runtime.universe.typeOf // 導入類型檢查器,其返回具體的類型,而不是類型擦除后的類型
import scala.reflect.runtime.universe.typeOf
scala> typeOf[singletonObj.type] // 返回對象的單例類型
res8: reflect.runtime.universe.Type = singletonObj.type
scala> val copyObj = singletonObj // 將單例類型復制給另一變量
copyObj: singletonObj.type = singletonObj$@4e25147a
scala> typeOf[copyObj.type] // 可以看出盡管是同一個對象,但是其單例類型不一樣,正是"任何對象都存在單例類型,且每個單例類型只有唯一的一個實例"
res10: reflect.runtime.universe.Type = copyObj.type

但是,如果現實設置obj的類型為singletonObj的單例類型呢?

scala> val obj:singletonObj.type = singletonObj // 將類型設定為singletonObj的單例類型
obj: singletonObj.type = singletonObj$@4e25147a
scala> typeOf[obj.type]  // 得到與singletonObj不同的單例類型
res11: reflect.runtime.universe.Type = obj.type
scala> typeOf[obj.type]==typeOf[singletonObj.type] // 其二個類型不相等
res12: Boolean = false
scala> typeOf[obj.type] <:< typeOf[singletonObj.type] // obj.type是singletonObj.type的子類
res15: Boolean = true
scala> typeOf[copyObj.type] <:< typeOf[singletonObj.type]
res16: Boolean = true// copyObj.type是singletonObj.type的子類
scala> typeOf[singletonObj.type] <:< typeOf[copyObj.type] 
res21: Boolean = true// singletonObj.type是copyObj.type的子類
scala> typeOf[singletonObj.type]==typeOf[copyObj.type] 
res22: Boolean = false// 但是兩者又不是同一類型

對于copyObj.type和singletonObj.type的關系和obj.type和singletonObj.type的關系是一樣的。

scala> val x:obj.type =singeltonObj
x: obj.type = singletonObj$@4e25147a // 既然不是同一類型,但是當x的類型顯示置為obj.type的時候卻又不會出現類型錯誤

而且,互相是對方的子類卻又不是同一類,此處 令人費解? 期待有心人給予解答

scala> copyObj.getClass
res34: Class[_ <: singletonObj.type] = class singletonObj$
scala> singletonObj.getClass
res36: Class[_ <: singletonObj.type] = class singletonObj$
scala> obj.getClass
res37: Class[_ <: singletonObj.type] = class singletonObj$
copyObj, singletonOjb,obj的類型都是 singletonObj$

非單例對象情況:

scala> class Klass
defined class Klass
scala> val c1 = new Klass // 創建Klass類的兩個對象
c1: Klass = Klass@3e4e8fdf
scala> val c2 = new Klass
c2: Klass = Klass@75156240
scala> val c3:c1.type = c2
<console>:17: error: type mismatch;
 found   : c2.type (with underlying type Klass)
 required: c1.type
       val c3:c1.type = c2  // 不同于單例對象中的情況,此處會出現 type mismatch錯誤
scala> typeOf[c1.type] <:< typeOf[c2.type]
res27: Boolean = false
scala> typeOf[c2.type] <:< typeOf[c1.type]
res28: Boolean = false
scala> typeOf[c1.type]==typeOf[c2.type]
res29: Boolean = false

同樣不同于單例對象中的情況,類Klass的兩個對象的單例類型,分別都不是對方的子類,且不相等。

scala> typeOf[c1.type] <:< typeOf[Klass]
res30: Boolean = true
scala> typeOf[c2.type] <:< typeOf[Klass]
res31: Boolean = true

但卻都是類Klass的子類。

雖然對象的單例類型不同,但是對象的類都是相同的

scala> c1.getClass
res32: Class[_ <: Klass] = class Klass
scala> c2.getClass
res33: Class[_ <: Klass] = class Klass

最常用的應用場景:鏈式調用

為模擬鏈式調用,首先定義兩個具有繼承關系的類

class A {  
    private var name:String=null 
    def setName(name:String)={   
       this.name = name   
       this // 返回調用對象 
   }
}
class B extends A{ 
      private var sex:String = null 
      def setAge(sex:String)={   
          this.sex=sex    
          this  
     }
}
object testApp{ 
     def main(args:Array[String]): Unit ={ 
          val a:A = new A
         val b:B = new B    
         b.setName("WangBa").setAge("woman")  // 無法執行 
         b.setAge("WangBa").setName("woman")  // 可以執行
     }
}

無法執行原因:
b.setName("WangBa") 返回對象的類型為A,但A類型沒有定義 setAge方法,所以無法執行
可以執行的原因:
b.setAge("woman") 返回的對象類型為B,B類型繼承了A類型定義的setName方法,所以可以執行

解決這種現象的方法是使用單例類型
將A,B類型的setName和setAge方法重新定義如下,就可以解決。

class A {  
     private var name:String=null 
     def setName(name:String):this.type={   
     this.name = name   
      this // 返回調用對象 
   }
}
class B extends A{ 
    private var sex:String = null 
    def setAge(sex:String):this.type={   
     this.sex=sex    
      this  
   }
}

添加方法的返回類型為自己的單例類型,而單例類型又是類的子類。
例如 b.setName("WangBa").setAge("woman") 在為改變A,B的方法定義之前,是不能執行的。更改后,b.setName的方法會類型是b.type(B的子類),因此便可以正常調用setAge方法了。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 1.OC里用到集合類是什么? 基本類型為:NSArray,NSSet以及NSDictionary 可變類型為:NS...
    輕皺眉頭淺憂思閱讀 1,394評論 0 3
  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,933評論 18 139
  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關的語法,內部類的語法,繼承相關的語法,異常的語法,線程的語...
    子非魚_t_閱讀 31,765評論 18 399
  • *面試心聲:其實這些題本人都沒怎么背,但是在上海 兩周半 面了大約10家 收到差不多3個offer,總結起來就是把...
    Dove_iOS閱讀 27,211評論 30 472
  • 當年高考的噩夢 卻變成如今我的黑色七月 無休止的加班任務 疲倦的雙眼 酸脹的雙肩 越來越暴躁的脾氣 無法宣泄的情緒...
    科瓦藍閱讀 117評論 0 0