Scala编程-第4章 类和对象- 高飞网

第4章 类和对象

2017-03-17 23:35:56.0

4.1 类、字段和方法

定义类:

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

    类中可以有字段和方法。字段用var或val修饰。如果要将状态封装在类内部,要加private修饰,默认是public的。

    类中可以定义方法。方法的入参都是val的,如果要在方法内部对入参赋值将会编译失败。

    def add(b:Byte):Unit={
        b = 2
        sum+=b;
    }

    编译结果:

class.scala:4: error: reassignment to val
		b = 2
                  ^
one error found

    以上的类定义正确地实现了预期功能,但不是推荐的写法,不够简洁。推荐的写法是没有return语句,也即把每个方法当作创建返回值的表达式。假设某个方法仅计算结果表达式,则可以去年花括号。

    如果没有发现任何显式的返回语句,Scala方法将返回方法中最后一次计算得到的值。

更简洁的类:

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

    上面的例子中,add方法没有返回值,只有副作用(即修改sum的值),在这时,可以将=Unit去掉,将方法体放在花括号里,在这种形式下,方法看上去很像过程(producure),一种仅为了副作用而执行的方法。

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

    比较容易出错的地方是如果去年方法体前面的等号,那么方法的结果类型就必定是Unit。

    这种廉洁不论方法体里面包含什么都成立,因为Scala编译器可以把任何类型转换为Unit。

    写等号就有返回值,不写就没有了。如

scala> def g()={"ni hao"}
g: ()String

scala> g
res1: String = ni hao

scala> def h(){"ni hao 2"}
<console>:11: warning: a pure expression does nothing in statement position
       def h(){"ni hao 2"}
               ^
h: ()Unit

scala> h


Scala中的分号不是必须的。

实例化对象:

val csa = new ChecksumAccumulator


4.3 Singleton对象

    Scala比Java更面向对象的特点之一是不能定义静态成员,而是代之以定义单例对象。除了object关键字替换了class关键字以外,单例对象的定义看上去与类定义一致。

object ChecksumAccumulator{
    private val cache = Map[String,Int]()
    def calcuate(s:String):Int={//定义校验和方法
        if(cache.contains(s)){//如果在缓存中有了
            cache(s)//直接返回
        }else{
            val acc = new ChecksumAccumulator //实例化对象
            for(c<-s)
                acc.add(c.toByte)//将字符计数sum
            val cs = acc.checksum()//得到校验和
            cache+=(s->cs)//放到缓存中
            cs//返回
        }
    }
}

    单例对象必须与之前的类放在一个文件中。

    单例对象叫做类的派生对象;类加作单例对象的伴生类。它们之间可以互相访问其私有成员。

    对于Java程序员来说,可以把单例对象当作是Java中可能会用到的静态方法工具类。也可以用类似的方法做调用:单例对象名.方法名

    类和单例对象间的差别是:单例对象不带参数,而类可以。

    单例对象不是用new关键字实例化的,所以没机会传递给它实例化参数。每个单例对象都被实现为虚构类(synthetis class)的实例,并指向静态的变量。单例对象在第一次访问的时候才会被初始化。


4.4 Scala程序

    要想编写能够独立运行的Scala程序,就必须创建有main方法(仅带一个参数Array[String],且结果类型为Unit)的单例对象。

import ChecksumAccumulator.calcuate
object Summer{
    def main(args:Array[String]){
        for(arg<-args)

println(arg+":"+calcuate(arg))

} }

上面第一行类似于Java中的静态引用,以允许后面直接调用方法名

    虽然Scala中不要求类名与文件名一致,但建立一致。

    对两个文件进行编译:

scalac ChecksumAccumulator.scala Summer.scala

    开始编译源文件,不过在编译完成之前或许会稍微停顿一下。这是因为每次编译器启动时,都要花一些时间扫描jar文件内容,并在开始编译你提交的文件之前完成更多其他的初始化 工作。因此Scala的发布包里还有一个叫fsc(fast scala compiler,快速Scala编译器)的Scala编译器后台服务。使用方法:

fsc ChecksumAccumulator.scala Summer.scala 
    第一次执行fsc时,会创建一个绑定在计算机端口上的本地服务器后台进程。然后会把文件列表通过端口发送给后台进程。由后台进程完成编译。下一次执行fsc时,检测到后台进程已经在运行了,于是fsc将只把文件列表发给后台进程,它会立刻开始编译文件。

完成编译之后,就可能用scala命令未执行了。

[java8@iZ25w5rxg9zZ a]$ scala Summer of love
of:-213
love:-182


4.5 Application特质

    使用特质后不用写main方法了

import ChecksumAccumulator.calcuate
object Summer extends App{
    for(season<-List("fall","winter","spring"))
        println(season+":"+calcuate(season))
}

注意:Application has been deprecated from scala 2.9, probably it has been deleted in scala 2.11 (it still exists in scala 2.10)