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