一个对象是一个只有一个实例的类。当它在被引用时将使用懒加载,就像一个懒加载的常量(只有要使用这个常量时,它才会被加载)。
作为一个顶级变量,一个对象就是一个单例。
作为一个类或局部变量的成员,它的行为几乎与就像一个懒加载的常量相同。
定义一个单例对象 (Defining a singleton object)
一个对象就是一个值。定义一个对象就像定义一个类一样。但是使用 object
关键字。
object Box
下面是一个有一个方法的对象的例子:
package logging
object Logger {
def info(message: String): Unit = println(s"INFO: $message")
}
这个 info
方法可以在程序的任何地方被导入使用。创建一个像这样的实用方法对单例对象来说是常用的。
让我们来看看怎么在另外一个包中使用 info
方法:
import logging.Logger.info
class Project(name: String, daysToComplete: Int)
class Test {
val project1 = new Project("TPS Reports", 1)
val project2 = new Project("Website redesign", 5)
info("Created projects") // Prints "INFO: Created projects"
}
因为导入语句 import logging.Logger.info
导入了 info
方法,所以可以直接使用。
导入需要一个“确定的路径”,而每一个对象都有一个确定的路径。
注意:如果一个对象不是顶级变量,而是在另一个类或对象内部,这个对象就是其它成员一样是“路径依赖”的。意思是说:如果给了两个饮料类,class Milk
和 class OrangeJuice
,一个类成员 object NutritionInfo
“依赖”于任何一个饮料类的实例。milk.NutritionInfo
对象与 oj.NutritionInfo
对象是完全不同的两个对象。
伙伴对象 (Companion objects)
如果一个对象的名字与一个类的名字完全相同,那么这个对象被称为伙伴对象。相对地,那个类被称伙伴类。一个伙伴类或伙伴对象能访问其伙伴的私有成员。没有实例化的伙伴类可以其伙伴对象的所有方法和属性。
import scala.math._
case class Circle(radius: Double) {
import Circle._
def area: Double = calculateArea(radius)
}
object Circle {
private def calculateArea(radius: Double): Double = Pi * pow(radius, 2.0)
}
val circle1 = new Circle(5.0)
circle1.area
Circle
类的每一个实例都有一个叫 area
的成员,而 object Circle
对象有一个 calculateArea
方法在其伙伴类中的每一个实例都使用了。
伙伴对象也可以定义工厂方法:
class Email(val username: String, val domainName: String)
object Email {
def fromString(emailString: String): Option[Email] = {
emailString.split('@') match {
case Array(a, b) => Some(new Email(a, b))
case _ => None
}
}
}
val scalaCenterEmail = Email.fromString("scala.center@epfl.ch")
scalaCenterEmail match {
case Some(email) => println(
s"""Registered an email
|Username: ${email.username}
|Domain name: ${email.domainName}
""")
case None => println("Error: could not parse email")
}
object Email
伙伴对象有一个 fromString
工厂方法,使用一个字符串创建一个 Email
实例。当 case 语句中解析出错时,将返回一个 Option[Email]
实例。
注意:如果一个类或者一个对象有伙伴,就必须都定义在同一个文件中。在 RERL 中定义一对伙伴也必须定义在同一行中或者进行 :paste
模式。
对 Java 程序员的建议 (Notes for Java programmers)
在 Java 中静态( static
)成员等同于 Scala 中伙伴对象中的普通成员。
当在 Java 代码中使用一个伙伴对象时,其成员将被定义其对应的伙伴类中并使用 static
关键字修饰。这叫作“静态转发”。它甚至发生在你根本没有定义对应的伙伴类时。