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

你可能感兴趣的:(Scala中单例类型及其使用场景)