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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,383评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,522评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,852评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,621评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,741评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,929评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,076评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,803评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,265评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,582评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,716评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,395评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,039评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,027评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,488评论 2 361
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,612评论 2 350

推荐阅读更多精彩内容

  • 1.OC里用到集合类是什么? 基本类型为:NSArray,NSSet以及NSDictionary 可变类型为:NS...
    轻皱眉头浅忧思阅读 1,368评论 0 3
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,637评论 18 139
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,599评论 18 399
  • *面试心声:其实这些题本人都没怎么背,但是在上海 两周半 面了大约10家 收到差不多3个offer,总结起来就是把...
    Dove_iOS阅读 27,135评论 30 470
  • 当年高考的噩梦 却变成如今我的黑色七月 无休止的加班任务 疲倦的双眼 酸胀的双肩 越来越暴躁的脾气 无法宣泄的情绪...
    科瓦蓝阅读 110评论 0 0