scala学习记录(4)

继承

知识点

继承类 extends

重写方法时必须用override

只有主构造器可以调用超类的主构造器

重写字段

抽象类、字段

扩展类

使用extends关键字

class Employee extends Person {...}

在子类中定义需要的新字段和方法,或者重写超类的方法

可将类声明为final,这样就不有被扩展

可将单个方法或字段声明为final,确保不能被重写

在上一节中,类有一个主构造器和任意多的辅助构造器,而每个辅助构造器都必须先调用先前定义的辅助构造器或主构造器为开始,调用超类构造器的方式也同样与类的定义交织在一起

class Employee(name: String, age: Int, val salary: Double) extends Person(name, age) {

}

说明:Employee类中有三个参数:name、age和salary,其中的name和age会被传递到超类中。相当于下面的Java代码

public class Employee extends Person {

    private String name;

    private int age;

    private double salary;

    public Employee(String name, int age, double salary) {

        super(name, age);

        this.salary = salary;

    }

}

重写方法

在Scala中重写一个非抽象方法必须使用override修饰符

class Pseron{

    override def toString = getClass.getName

}

在Scala中调用超类的方法用supper关键字

class Employee extends Pseron{

    override def toString = super.toString + getClass.getName

}

重写字段

可以用另一个同名的val字段重写一个val或不带参数的def

常见操作是用val重写抽象的def

abstract class Person{

    def id: Int

}

class Student(override val id: Int) extends Person

重写时注意如下限制

def只能重写另一个def

val只能重写另一个val或不带参数的def

var只能重写另一个抽象的val

抽象类

用abstract关键字标记的类不能被实例化

抽象类通常包含某个或几个方法没有被完整定义

与Java不同,不需要对抽象方法使用abstract关键字,只是省去了方法体

如果某个类至少存在一个抽象方法,则该类必须声明为abstract

子类中重写超类中抽象方法时,不需要使用override关键字

抽象字段

抽象字段就是一个没有初始值的字段

abstract class Person{

    val id: Int

    var name: String

}

具体的子类必须提供具体的字段

和方法一样,在子类中重写超类中的抽象字段时,不需要override关键字

特质

知识点

Scala和Java一样不允许类继承多个超类,特质解决这一局限性

类可以实现任意数量的特质

当将多个特质叠加在一起时,顺序很重要,其方法先被执行的特质排在更后面

Scala特质可以提供方法和字段的实现

特质要求实现它们的类具备特定的字段、方法或超类

特质可以同时拥有抽象方法和具体方法,而类可以实现多个特质

当做接口使用的特质

Scala特质完全可以像Java的接口一样,使用关键字 trait

不需要将方法声明为abstract,特质中未被实现的方法默认就是抽象的

在子类中重写特质的抽象方法不需要用 override 关键字

package com.gemantic.base

/**

  * @author Yezhiwei

  * @date 18/1/6

  */

object TraitLearn {

  def main(args: Array[String]): Unit = {

    val logger = new ConsoleLogger

    logger.log("console log message...")

  }

}

trait Logger {

  def log(msg: String)

}

class ConsoleLogger extends Logger {

  override def log(msg: String): Unit = println(msg)

}

说明:

子类实现特质,用 extends 而不是 implements

不需要写 override

如果需要多个特质,可以用with关键字来添加额外的特质,如下代码

class ConsoleLogger extends Logger with Serializable {

  override def log(msg: String): Unit = println(msg)

}

带有具体实现的特质

在Scala的特质中的方法并不需要一定是抽象的

子类从特质得到了一个具体的log方法实现

trait ConsoleLoggerImp {

  def log(msg: String) {println(msg)}

}

class AccountAction extends Account with ConsoleLoggerImp {

  def withdraw(amount: Double): Unit = {

    if (amount > nowBalance) {

      log("insufficient funds")

    } else {

      log("enough funds")

    }

  }

}

object TraitLearn {

  def main(args: Array[String]): Unit = {

    // 当做接口使用的特质

    val logger = new ConsoleLogger

    logger.log("console log message...")

    // 带有具体实现的特质

    val accountAction = new AccountAction

    accountAction.withdraw(1000)

  }

}

带有特质的对象

在构造单个对象时,可以为它添加特质

在定义子类时可以使用不做任何实现的特质,在构造具体对象的时候混入一个更合适的实现

特质中重写抽象方法,必须在方法上使用 abstract 及 override

// 有默认实现,但是什么也没有做

trait Logged {

  def log(msg: String) {}

}

trait FileLogged extends Logged {

  override def log(msg: String): Unit = println("saving file : " + msg)

}

class AccountAction extends Account with Logged {

  def withdraw(amount: Double): Unit = {

    if (amount > nowBalance) {

      log("insufficient funds")

    } else {

      log("enough funds")

    }

  }

}

object TraitLearn {

  def main(args: Array[String]): Unit = {

    // 带有特质的对象,可以混入不同的日志

    val accountActionLogger = new AccountAction with FileLogged

    accountActionLogger.withdraw(1000)

  }

}

// 运行输出结果

saving file : insufficient funds

叠加在一起的特质

可以为类或对象添加多个互相调用的特质,从最后一个开始被处理

// 为日志增加时间戳

trait TimestampLogged extends Logged {

  override def log(msg: String): Unit = super.log(new java.util.Date() + " " +  msg)

}

// 如果日志内容长度超过10,截断

trait ShortLogged extends Logged {

  override def log(msg: String): Unit = super.log(if (msg.length <= 10) msg else msg.substring(0, 10) + "...")

}

object TraitLearn {

  def main(args: Array[String]): Unit = {

    // 带有特质的对象

    val accountActionLogger = new AccountAction with FileLogged with TimestampLogged with ShortLogged

    accountActionLogger.withdraw(1000)

    val accountActionLogger1 = new AccountAction with FileLogged with ShortLogged with TimestampLogged

    accountActionLogger1.withdraw(1000)

  }

}

// 输出结果为

saving file : Sat Jan 06 12:38:07 CST 2018 insufficie...

saving file : Sat Jan 06...

注意上面的特质调用顺序及log方法每一个都将修改过的消息传递给supper.log

特质构造顺序

和类一样,特质也可以有构造器,由字段的初始化和其他特质体中的语句构成

构造器执行顺序

首先调用超类的构造器

特质构造器在超类构造器之后、类构造器之前执行

特质由左到右被构造

每个物质当中,父特质先被构造

如果多个特质共有一个父特质,而那个父特质已经被构造,则不会再次构造

所有的特质构造完毕,子类被构造

示例

class AccountAction extends Account with FileLogged with ShortLogged {

    ...

}

构造器执行顺序如下

超类 Account

Logged ,第一个特质的父特质

FileLogged 第一个特质

ShortLogged 第二个特质,它的父特质Logged已被构造

AccountAction 子类
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值