Scala学习笔记二

第四章 类和对象

4.1 类,字段和方法

假设有这样的类:

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

由于函数体只有一句话,因此可以去掉外面的大括号;另外,checksum方法最后的return语句是多余的可以去掉。如果没有发现任何显式的返回语句,Scala方法将返回方法中最后一个计算得到的值。将代码简化成如下所示:

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

由于add方法的结果类型为Unit,执行的目的就是它的副作用。例如add的副作用就是sum被重新赋值了。这种情况下可以去掉等号和结果类型,把方法放在大括号里,如下所示:

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

注意,如果没写结果类型,但是写了“=”,那么编译器会根据最后返回值的类型确定函数结果类型;若是去掉了结果类型和“=”,那么函数的结果类型一定为Unit。
scala能将任何类型转换为Unit,但是转换后原来的值就丢失了。看下面的例子

//定义一个不带“=”的函数
scala> def g() {"hello world"}
//编译结果
g: ()Unit
//使用println输出g
scala> println(g)
//输出结果
()
//定义一个带“=”的函数
scala> def f() = {"hello world"}
//编译结果
f: ()String
//使用println输出f
scala> println(f)
//输出结果
hello world
4.2 分号推断

  Scala程序里,语句末尾的分号通常是可选的。如果你愿意可以输入一个,但若一行里仅有一个语句也可不写。另一方面,如果一行里写多个语句那么分号是需要的

4.3 Singleton对象

  scala中没有静态成员,取而代之的是单例对象Singleton Object,使用object关键字来定义。
  伴生对象与伴生类:若某个单例对象和某个类共享同一个名称,那么这个单例对象称为这个类的伴生对象,这个类被称为这个对象的伴生类。类和它的伴生对象可以相互访问其私有成员。
  有如下代码:

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
}
}

  这个object和上一小节定义的类同名,因此为该类的伴生对象,可以访问其中的私有成员变量和方法。
  该对象有一个名为cache的私有成员变量,以及一个名为calculate的方法。在calculate方法中对于传入的String类型的参数s,首先判断cache中是否存在,若存在则返回该key对应的value;若不存在,则创建一个ChecksumAccumulator对象,调用该对象的add()方法和checksum()方法,最后将结果存入到cache中。
  单例对象中的方法可以使用“类名.方法名”来直接调用,而不用new一个对象。类可以带参数,但单例对象不带参数(没法通过new来实例化单例对象)。单例对象会在第一次被访问的时候初始化。
  在java里类名必须和文件名相同,但在scala里却不一定。

注意:也有的object并没有共享名称的类,这类单例对象称为“孤立对象”。使用场景:把相关的功能收集在一起(如将某一类的transfer功能都放到某个object中)或定义一个scala应用的入口(如在object里写一个main()方法成为应用的入口)

4.4 Scala的Application特质

有如下代码:

import ChecksumAccumulator.calculate object FallWinterSpringSummer extends Application { 
for (season <- List("fall", "winter", "spring")) 
println(season +": "+ calculate(season)) }

  通过继承Application,可以不用写main方法,而是直接在大括号里写方法体就,然后直接点击运行就可以被运行。
  原理:Trait Application声明了带有合适的签名的main方法,并由上面的单例对象继承,使它可以像个Scala程序那样用。大括号之间的代码被收集进了单例对象的主构造器,并在类被初始化时被执行。
  继承自Application比写个显式的main方法要短,不过它也有些缺点。首先,如果想访问命令行参数的话就不能用它,因为args数组不可访问。第二,因为某些JVM线程模型里的局限,如果程序是多线程的就需要显式的main方法。最后,对于某些JVM,Application中执行的对象的初始化代码并不会被优化。因此只有当你的程序相对简单和单线程情况下你才可以继承Application特质。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值