Scala比 Java 更面向对象的一个方面是 Scala 没有静态成员。替代品是,Scala 有: 单例对象:singleton object。
除了用 object 关键字替换了 class 关键字以外,单例对象的定义看上去就像是类定义。
1、表中的单例对象被叫做 ChecksumAccumulator ,与前一个例子里的类同名。当单例对象与
某个类共享同一个名称时,他被称作是这个类的 伴生对象:companion object。你必须在
同一个源文件里定义类和它的伴生对象。类被称为是这个单例对象的 伴生类:companion
class。类和它的伴生对象可以互相访问其私有成员。
ChecksumAccumulator 单例对象有一个方法, calculate ,用来计算所带的 String 参数中字
符的校验和。它还有一个私有字段, cache ,一个缓存之前计算过的校验和的可变映射。
2、方法的第一行,“ if (cache.contains(s)) ”,检查缓存,看看是否传递进来的字串已经作为
键存在于映射当中。如果是,就仅仅返回映射的值,“ cache(s) ”。否则,执行 else 子句,
计算校验和。 else 子句的第一行定义了一个叫 acc 的 val 并用新建的 ChecksumAccumulator
实例初始化它。
3、如果你是 Java 程序员,考虑单例对象的一种方式是把它当作是或许你在 Java 中写过的任
何静态方法之家。可以在单例对象上用类似的语法调用方法:单例对象名,点,方法名。
例如,可以如下方式调用 ChecksumAccumulator 单例对象的 calculate 方法:
下一行是个 for 表达式,对传入字串的每个字符循环一次,并在其上调用
toByte 把字符转换成 Byte ,然后传递给 acc 所指的 ChecksumAccumulator 实例的 add 方法。
完成了 for 表达式后,下一行的方法在 acc 上调用 checksum ,获得传入字串的校验和,并存
入叫做 cs 的 val 。下一行,“ cache += (s -> cs) ”,传入的字串键映射到整数的校验和值,
并把这个键-值对加入 cache 映射。方法的最后一个表达式,“ cs ”,保证了校验和为此方法
的结果。
1、 这里我们使用了缓存例子来说明带有域的单例对象。像这样的缓存是通过内存换计算时间的方式做到性
能的优化。通常意义上说,只有遇到了缓存能解决的性能问题时,才可能用到这样的例子,而且应该使用
弱映射(weak map),如 scala.Collection.jcl 的 WeakHashMap ,这样如果内存稀缺的话,缓存里的条
目就会被垃圾回收机制回收掉。
2、 因为关键字new 只用来实例化类,所以这里创造的新对象是 ChecksumAccumulator 类的一个实例,而不是同名的单例对象。
单例对象调用过程: