类和对象之类与字段和方法

类是对象的蓝图,一旦你定义了类,就可以用关键字new根据类的蓝图创建对象。类定义里,可以放置字段和方法,这些被笼统地称为成员。字段,不管是用val还是用var定义的,都是指向对象的变量。方法,用def定义,包含了可执行的代码。字段保留了对象的状态或数据,而方法使用这些数据执行对象的运算工作。如例,定义了ChecksumAccumulator类并内置名为sum的var字段:

class ChecksumAccumulator{
  var sum = 0;
}

然后实例化两次:

val acc = new ChecksumAccumulator
val csa = new ChecksumAccumulator

每一个实例都有自己的变量集。如果你改变acc对象的sum变量值,而csa对象的sum值是不会一起跟着改变的,因为它们都属于各自的对象(跟Java是一样的)。另外还需要注意的是,尽管acc,csa都是val的,但仍可以修改它们所指向的对象。val类型的限制仅在于不可以把它们(acc,csa)再次赋值为其他对象(这一点跟Java的final关键字使用是一样的)。因此,我们可以得出结论:val的acc,csa将始终指向初始化时的ChecksumAccumulator对象,但是对象包含的字段可以随时改动

Scala中,字段可以申明为私有的。通过把字段变为私有的(private)以阻止外界直接对它的访问,因为私有字段只能被定义在同一个类里的方法访问,所有能更新字段的代码将被锁定在类里。要声明字段是私有的,可以把访问修饰符private放在字段的前面(这与java使用private关键字相同),如例:

class ChecksumAccumulator{
  private var sum = 0;
}

现在sum是私有的,所以唯一能访问sum的代码都定义在类的内部。

203311_ZCXl_168814.jpg

如上例:acc.sum = 5         //编译不过,因为sum是私有的。
注意在scala里把成员变量公开的方法是不显式地指定任何访问修饰符。换句话说,在java里要写上“public”的地方,在scala里只要什么都不要写就成。public是scala方法的默认访问级别。上面的例子,除非我们定义其它什么方法,否则ChecksumAccumulator对任何人都没有什么用处:

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

现在ChecksumAccumulator有两个方法了,add和checksum。
传递给方法的任何参数都可以在方法内部使用。Scala里方法参数的一个重要特征是:它们都是val的,不是var的。如果你想在方法里面给参数赋值,编译会失败。如例:

203804_ikmW_168814.jpg

尽管ChecksumAccumulator在这个版本里的add与checksum方法正确地实现了预期的功能,但还不够简洁。首先,checksum方法最后的return语句是多余的可以去掉。如果没有发现任何显式的返回语句,scala方法将返回方法中最后一次计算得到的值。如例:

204017_Emcg_168814.jpg

方法的推荐风格是尽量避免使用返回语句,尤其是多条返回语句。代之以把每个方法当作是创建返回值的表达式。这种逻辑鼓励你分层简化方法,把较大的方法分解为多个更小的方法。另一方面,内容决定形式,如果确实需要,scala也能够很容易地编写具有多个显式的return的方法。
接着上面那个ChecksumAccumulator类,checksum只要计算值,不用return。所以这个方法有另一种简写方式:假如某个方法仅计算单个结果表达式,则可以去掉花括号。如果结果表达式很短,甚至可以把它放在def的同一行里。这样改动之后,ChecksumAccumulator看上去像这样:

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

对于像ChecksumAccumulator的add方法那样的结果类型为Unit的方法来说,执行的目的就是为了它的副作用。通常我们定义副作用为能够改变方法之外的某处状态或执行I/O活动的方法。比方说,在add这个例子里,副作用就是sum被重新赋值了。它的另一种表达方式是去掉结果类型和等号,把方法体放在花括号里。在这种形式下,方法看上去很像过程(procedure),一种仅为了副作用而执行的方法。如例,add方法可以改写如下:

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

比较容易出错的地方是:如果去掉方法体前面的等号,那么方法的结果类型就必定是Unit。这种说法不论方法体里面包含什么都成立,因为Scala编译器可以把任何类型转换为Unit。例如,如果方法的最后结果是String,但结果类型被声明为Unit,那么String将被转变为Unit并丢弃原值:

204658_GU5z_168814.jpg

例子里,函数f声明了结果类型Unit,因此String被转换为Unit。带有花括号但没有等号的,本质上当作Unit结果类型的方法,例如:

204936_wehY_168814.jpg

因此,对于本想返回非Unit值的方法却忘记加等号时,错误就出现了。所以为了得到想要的结果,等号是必不可少的:

205033_dQF4_168814.jpg

转载于:https://my.oschina.net/fhd/blog/273972

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值