不属于类单个实例的方法和值属于单例对象,用关键字object
而不用class
来标记。
package test
object Blah {
def sum(l: List[Int]): Int = l.sum
}
这个sum
方法是全局可用的,并且可以用test.Blah.sum
来引用或引入。
单例对象某种程度来说是定义一个单一使用类,不能直接实例化,并且在object
定义处有一个同名的val
成员。实际上,像val
,单例对象可以被定义为一个特征或类的成员,虽然这不是典型用法。
单例对象可以扩展类和特征。实际上,不带type parameters的Case类会默认创建一个同名的单例对象,实现了特征[Function*]。
伴生
大部分单例对象不是独立的,而是和相同名字的类关联。前面提到的Case类的同名单例对象,就是一个例子。这种情况下,单例对象被称为类的伴生对象(companion object)
,类称为对象的伴生类(companion class)
。
Scaladoc对类和其伴生对象之间跳转做了特殊支持:可以点击大的"C"或者"O"圆圈图标跳转到伴生对象。
class IntPair(val x: Int, val y: Int)
object IntPair {
import math.Ordering
implicit def ipord: Ordering[IntPair] =
Ordering.by(ip => (ip.x, ip.y))
}
看到typeclass示例作为implicit values是很常见的,如上面的在伴生中定义的ipord
。这是因为伴生成员包含在相关值的默认隐式搜索中。
给Java程序员提示
Scala中static
不是一个关键字。相反,所有成员都是静态的,包括类,都应该归为单例对象。它们可以用相同的语法引用,单独或者作为一个整体被引入等等。
Java程序员会频繁定义静态成员,也许是private
的,作为实例成员的辅助实现。这些都转为使用伴生对象,一种常用模式是在类中引入伴生对象的成员。如下:
class X {
import X._
def blah = foo
}
object X {
private def foo = 42
}
这种使用方式展现了另外一个特性:在private
上下文中,类和它的伴生对象是友元。object X
可以访问class X
的私有成员,反之亦然。想要有真正的私有成员,使用private[this]
。
为了给Java提供方便,在单例对象中直接定义的方法(包括var
和val
)也会在伴生类中定义静态方法,叫做static forwarder
。对于object X
,其它成员可以用X$.MODULE$
静态字段访问。如果你把所有实现都放在伴生对象中并且发现就剩下一个不用实例化的类了,那就把类删掉。static forwarder
仍然会被创建。
网友评论