Scala 继承

摘自《快学Scala》

0.重点

  • extends,final关键字和Java中相同
  • 重写方法时必须用override
  • 只有主构造器可以调用超类的主构造器
  • 可以重写字段
  • 本章只探讨类继承自另一个类的情况

1.扩展类

class Employee extends Person{
    var salary = 0.0
}

和Java一样,将类声明为final,就不能被扩展了。

2.重写方法

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

public class Person{
    ...
    override def toString = getClass.getName + "[name=" + name + "]"
}

override修饰符可以给出有用的错误提示
* 当你拼错了要重写的方法名
* 当你不小心在新方法中使用了错误的参数类型
* 当你在超类中引入了新的方法,而这个新方法与子类的方法相抵触】

Scala中调用超类的方法:super关键字。

public class Employee extends Person{
    ...
    override def toString = super.toString + "[salary=" + salary + "]"
}

super.toString会调用超类的toString方法——即Person.toString

类型检查和转换

要测试某个对象是否属于某个给定的类,可以用isInstanceOf方法。如果测试成功,就可以用asInstanceOf方法将引用转换为子类的引用:

if (p.isInstanceOf[Employee]){
    val s = p.asInstanceOf[Employee] //s的类型为Employee
}

// 如果你想要测试p指向的是一个Employee对象但又不是其子类,可以用:
if(p.getClass == classOf[Employee])

与类型检查和转换相比,模式匹配是更好的选择:

p match{
    case s:Employee => ...
    case _ => //p不是Employee
}

4.受保护字段和方法

同Java和C++一样,可以将字段或方法声明为protected,这样的成员可以被任何子类访问,但不能从其他位置看到。
与Java不同,protected的成员对于类所属的包而言,是不可见的。
Scala还提供了一个protected[this]的变体,将访问权限限定在当前对象。类似private[this].

5.超类的构造

6.重写字段

class Person(val name:String){
    override def toString = getClass.getName + "[name= + name + "]"
}

class SecretAgent(codename:String) extends Person(codename){
    override val name = "secret" 
    override val toString = "secret"
}

更常见的案例是用val重写抽象的def,就像这样:

abstract class Person{
    def id:Int 
    ...
}
class Student(override val id:Int) extends Person //学生id通过构造器输入

7.匿名子类

val alien = new Person("Fred"){
    def greeting = "Greetings, Earthling! My name is Fred."
}

def meet(p:Person{def greeting:String}){
    println(p.name + "says:" + p.greeting)
}

8.抽象类

和Java一样,可以用abstract关键字来标记不能被实例化的类,通常这是因为它的一个或几个方法没有被完整定义。例如:

abstract class Person(val name:String){
    def id:Int //没有方法体,这是个抽象方法
}

如果某个类至少存在一个抽象方法,则该类必须声明为abstract。
在子类中写超类的抽象方法时,不需要使用override关键字。

class Employee(name:String) extends Person(name){
    def id = name.hashCode // 不需要override关键字
}

9.抽象字段

抽象字端就是一个没有初始值的字段。如:

abstract class Person{
    val id:Int //没有初始化——这是一个带有抽象的getter方法的抽象字段
    var name:String //另一个抽象字段,带有抽象的getter和setter方法
}

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

class Employee(val id:Int) extends Person{ //子类有具体的id属性
    var name=""//和具体的name属性
}

可以随时用匿名类型来定制抽象字段:

val fred = new Person{
    val id = 1729
    var name = "Fred"
}

10.构造顺序和提前定义

class Creature{
    val range:Int = 10
    val env:Array[Int] = new Array[Int](range)
}

class Ant extends{
    override val range = 2
}with Creature

提前定义的等号右侧只能引用之前已有的提前定义,而不能使用类中的其他字段或方法。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值