Scala学习笔记04【类和对象】

1、类,字段和方法

类的定义及创建对象:

class ChecksumAccumulator 
{   
    ...//类定义里,可以放置字段和方法,这些被笼统地称为成员:member。
} 

创建ChecksumAccumulator对象:

new CheckSumAccumulator 

又:

class ChecksumAccumulator 
{   
    var sum = 0
} 

val acc = new ChecksumAccumulator  //acc.sum = 0 
val csa = new ChecksumAccumulator  //csa.sum = 0 

acc.sum = 3  //acc.sum = 3 , csa.sum = 0 

对acc(或csa)不能做的事情是由于它们是val,而不是var,你不可以把它们再次赋值为不同的对象。

// 编译不过,因为acc是val 
acc = new ChecksumAccumulator 

要声明字段是私有的,可以把访问修饰符private放在字段的前面,就像这样:

class ChecksumAccumulator {      
    private var sum = 0 
} 

有了这个ChecksumAccumulator的定义,任何从类外部访问sum的尝试都会失败:

val acc = new ChecksumAccumulator  
acc.sum = 5 //编译不过,因为sum是私有的 

在Scala里把成员公开的方法是不显式地指定任何访问修饰符(即public可以省略)。

定义方法:

class ChecksumAccumulator {      
    private var sum = 0  

    def add(b: Byte): Unit =    //参数b类型是val
    {          
        sum += b      
    }    

    def checksum(): Int = 
    {          
        return ~(sum & 0xFF) + 1     //“return”是多余的
    }  
} 

传递给方法的任何参数都可以在方法内部使用。
Scala里方法参数的一个重要特征是它们都是val,不是var(即参数b类型是val)。

return语句是多余的:
如果没有发现任何显式的返回语句,Scala方法将返回方法中最后一个计算得到的值

方法返回值问题(“=”的使用):

def f(): Unit = "abc"         // f: ()Unit 

def g() { "abc" }           //g: ()Unit 

def h() = { "abc" }             // h: ()java.lang.String 返回String

2、分号推断

Scala程序里,语句末尾的分号通常是可选的。
如果一行里写多个语句那么分号是需要的:

val s = "hello"; println(s) 

代码

x  
+ y

会被分成两个语句x和+ y。

希望把它作为一个语句x + y,你可以把它包裹在括号里:

(x  
+ y) 
或
x +
y

在串接类似于+的中缀操作符,把操作符放在行尾而不是行头是普遍的Scala风格:

x +  
y +  
z       //相当于x + y + z

分号推断的规则

除非以下情况的一种成立,否则行尾被认为是一个分号:

1.疑问行由一个不能合法作为语句结尾的字结束,如句点或中缀操作符。

2.下一行开始于不能作为语句开始的字。

3.行结束于括号(…)或方框[…]内部,因为这些符号不可能容纳多个语句。

3、Singleton对象

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

除了用object关键字替换了class关键字以外,单例对象的定义看上去就像是类定义:

//单例对象
import scala.collection.mutable.Map  

object ChecksumAccumulator 
{    
  private val cache = Map[String, Int]()

  def calculate(s: String): Int =        //计算所带的String参数中字符的校验和
        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          
        }  
} 

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

调用ChecksumAccumulator单例对象的calculate方法:

ChecksumAccumulator.calculate("Every value is an object.") 

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

因为不能用new关键字实例化一个单例对象,没机会传递给它参数。

每个单例对象都被作为由一个静态变量指向的虚构类:synthetic class的一个实例来实现。
因此它们与Java静态类有着相同的初始化语法,单例对象会在第一次被访问的时候初始化。

4、Scala程序

执行Scala程序,要提供一个有main方法的孤立单例对象名:

import ChecksumAccumulator.calculate  

object Summer 
{      
    def main(args: Array[String]) 
        {          
            for (arg <- args)              
                println(arg + ": " + calculate(arg))      
        }  
} 

注意:
Scala隐式引用了包java.lang和scala的成员,和名为Predef的单例对象的成员,到每个Scala源文件中。

5、Application特质

Scala提供了一个特质,scala.Application,可以节省一些手指的输入工作。

实例:

import ChecksumAccumulator.calculate  

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

使用这个特质的方法是,首先在你的单例对象名后面写上”extends Application” 。
然后代之以main方法,你可以把想要放在main方法里的代码直接放在单例对象的大括号之间。

继承自Application比写个显式的main方法要短。

缺点:
首先,如果想访问命令行参数的话就不能用它,因为args数组不可访问。
第二,因为某些JVM线程模型里的局限,如果程序是多线程的就需要显式的main方法。

你可能感兴趣的:(scala,类,对象,Class)