在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方法了。