scala编程(四)——类和对象

 类,字段和方法

在scala里定义一个典型的类,代码如下:

class ChecksumAccumulator {
private var sum = 0
def add(b: Byte): Unit = {
sum += b
}
def checksum(): Int = {
return ~(sum & 0xFF) + 1
}
}

1.在 Scala 里成员公开的方法是不显式地指定任何访问修饰符。换句话说,你在 Java 里要写上 “public”的地方,在 Scala 里只要什么都不要写就成。Public 是 Scala 的缺省访问级别。

2.Scala里方法参数的一个重要特征是它们都是val,不是var。如果你想在方法里面给参数重新赋值,结果是编译失败:

def add(b: Byte): Unit = {
   // b += 1
    sum += b
  }

3.如果没有发现任何显式的返回语句,Scala 方法将返回方法中最后一个计算得到的值。假如某个方法仅计算单个结果表达式,则可以去掉大括号。如果结果表达式很短,甚至可 以把它放在 def 同一行里。

所以上面的checksum方法可以改写如下:

def checksum(): Int = ~(sum & 0xFF) + 1

4.当你去掉方法体前面的等号时,它的结果类型将注定是 Unit。 不论方法体里面包含什么都不例外,因为 Scala 编译器可以把任何类型转换为 Unit。另外,如果方法的最后结果是 String,但方法的结果类型被声明为 Unit,那么 String 将被转变 为 Unit 并失去它的值。

def checksum2() {~(sum & 0xFF) + 1}
  def checksum3():Unit = "hello";

Singleton对象

Scala 比 Java 更面向对象的一个方面是 Scala 没有静态成员。替代品是,Scala 有单例对象:singleton object

 创建ChecksumAccumulator类的“伴生对象”:

// 文件 ChecksumAccumulator.scala
import scala.collection.mutable.Map
object ChecksumAccumulator {
  private val cache = Map[String, Int]()
  def calculate(s: String): Int =
    if (cache.contains(s))
      cache(s)
    else {
      val acc = new ChecksumAccumulator
      for (c <- s)
        acc.add(c.toByte)
      val cs = acc.checksum()
      cache += (s -> cs)
      cs
    }
}

表中的单例对象被叫做 ChecksumAccumulator,与前一个例子里的类同名。当单例对象与 某个类共享同一个名称时,他被称作是这个类的伴生对象companion object。你必须在 同一个源文件里定义类和它的伴生对象。类被称为是这个单例对象的伴生类companion class。类和它的伴生对象可以互相访问其私有成员。

单例对象扩展了超类并可以混入特质。由于每个单例对象都是超类的实例并混入了特质,你可以通过这些类型调用它的方法,用这些类型的变量指代它,并把它传递给需要这些类型的方法。

类和单例对象间的一个差别是,单例对象不带参数,而类可以。因为你不能用new关键字 实例化一个单例对象,你没机会传递给它参数。每个单例对象都被作为由一个静态变量指向的虚构类:synthetic class的一个实例来实现,因此它们与Java静态类有着相同的初始 化语法。4 4.4 Scala 程序 特别要指出的是,单例对象会在第一次被访问的时候初始化。

不与伴生类共享名称的单例对象被称为孤立对象:standalone object。由于很多种原因你 会用到它,包括把相关的功能方法收集在一起,或定义一个 Scala 应用的入口点。

Scala 程序

要执行 Scala 程序,你一定要提供一个有 main 方法(仅带一个参数,Array[String],且 结果类型为 Unit)的孤立单例对象名。任何拥有合适签名的 main 方法的单例对象都可以 用来作为程序的入口点。

 

注意 Scala 隐式引用了包 java.lang 和 scala 的成员,和名为 Predef 的单例对象的成员,到每个 Scala 源文件中。Predef,被放置在包 scala 中,包含了许多有用的方法。例如,当在 Scala 源文件中写 pringln 的时候,你实际调用了 Predef 的 println。(Predef.pringln 运转并调用 Console.println,做实际的工 作。)当你写 assert,你是在调用 Predef.assert。

接下来,我们在main方法中完成对上述ChecksumAccumulator类和单列对象的调用,代码如下:

object Summer {
  def main(args: Array[String]) {
    val args2 = List("hello","hi");
    for (arg <- args2)
      println(arg + ": " + calculate(arg))
  }
}

程序的运行结果如下:

hello: -20
hi: -209

相关推荐