快学Scala之继承
## 1. 继承
Scala语言通过 extends 关键字来继承类.
那么继承一个类有什么好处呢? 子类除了拥有继承自超类的方法和字段(即为val(常量), var(变量)所定义的), 还可以添加自己需要的新方法和新字段, 而且不但可以重写(override)超类的方法, 还可以重写超类的`字段`.
### final 关键字
在Scala中, 不仅可以将类声明为final, 而且可以将字段和方法声明为final
当类被声明为final时, 类不可以被继承; 当方法和字段被声明为final时, 对应的方法和字段不可以被子类重写, 看看下面这个例子就一目了然
```scala
class Person {
final val key = 0
val e = 1
}
class Kid extends Person {
// 报错: Value 'key' can not override final member
// override val key = 1
override val e = 2
}
object test extends App {
val k = new Kid;
println(k.key)
println(k.e)
}
/*output
0
2
*/
```
## 2. 重写方法
在Scala中重写一个非抽象方法`必须`使用`override`修饰符, 如:
```scala
override def toString: String = getClass.getName + "[name=" + name + "]"
```
override修饰符可以在多个常见的情况下给出有用的错误提示, 包括:
1. 当你拼错了要重写的方法名和字段名
2. 当你不小心在新方法中使用了错误的参数类型
3. 当你在超类中引入了新方法, 而这个新方法和子类的方法抵触
Scala语言使用`super`关键字调用超类的方法, super.toString 相当于Person.toString
```scala
class Person {
final val key = 0
val name = "person"
val age = 1
override def toString: String = getClass.getName + "[name=" + name + "]"
}
class Kid extends Person {
//override val key = 1
override val name = "kid"
override val age = 2
override def toString: String = super.toString + "[age=" + age + "]"
}
object test extends App {
val k = new Kid;
println(k.key)
println(k.age)
println(k)
}
/*output
0
2
chap08.Kid[name=kid][age=2]
*/
```
## 3. 类型检查和转换
Scala语言中可以使用 isInstanceOf[T] 方法, 测试某个对象实际类型是否属于某个给定类T或者类T的子类; 测试成功之后可以用 asInstanceOf[T] 方法将对象引用转化为的(子类)类T引用(一般来说对象的引用类型是T的父类, 而实际类型是T或者T的子类)
```scala
if (kid.isInstanceOf[Kid]) {
val s = kid.asInstanceOf[Kid]
}
```
如果kid是null, 则 kid.isInstanceOf[Kid] 返回false, kid.asInstanceOf[Kid] 返回null, 如果kid不是一个Kid, kid.asInstanceOf[Kid]将抛出异常
如果要测试kid指向Kid类又不是其子类, 使用如下方法:
```scala
if (kid.getClass == classOf[Kid]) {
val s = kid.asInstanceOf[Kid]
}
```
## 4. 超类构造
类有一个主构造器和任意数量的辅助构造器, 而每个辅助构造器都必须以对先前定义的辅助构造器或者主构造器的调用开始, 这样做的结果就是:
辅助构造器`永远都不可能`直接调用超类的构造器; 子类的辅助构造器最终都会调用主构造器; 只有主构造器而已调用超类的构造器.
主构造器是和类的定义交织在一起, 调用超类的构造器同样也交织在一起
```scala
class Kid(gender: String, val height: Double) extends Person(gender)
```
Kid类有2个参数, 一个被"传递"到超类
> scala语言的(主)构造器中, 你不能调用super(paras)
## 5. 重写字段
>Scala的字段(Fields)由一个私有字段和取值器/改值器方法构成
你可以用一个同名的val字段重写一个val或者不带参数的def, 子类有一个私有字段和一个共有的getter方法, 而这个getter方法重写了超类的getter方法.
```scala
class Smiler(val happy: String) {
override def toString: String = getClass.getName + "[happy: " + happy + "]"
}
class Laughter(veryhappy: String) extends Smiler(veryhappy) {
override val happy: String = "Laughter"
override val toString: String = super.toString
}
```
更常见的例子是 val 重写抽象的 def,就像这样:
```scala
abstract class Smiler(val happy: String) {
def degree: Int
}
class Laughter(lhappy: String, override val degree: Int) extends Smiler(lhappy) {
}
```
注意如下限制:
* def 只能重写另一个def
* val 只能重写另一个val或者不带参数的def
* var 只能重写另一个抽象的var
## 6. 匿名子类
你可以通过包含带有定义或重写的代码块的方式创建一个匿名子类,比如
```scala
val alien = new Person("good") {
def greeting = "hi, good"
}
```
## 7. 抽象类 与 抽象字段
* 不需要对抽象方法和抽象字段用abstract关键字
* 子类中重写超类的抽象方法和抽象字段时, 不需要`override`关键字
* 只要类中存在抽象方法, 该类必须声明为 abstract
### 7.1 抽象类
Scala中使用 abstract关键字来标记不能实例化的类, 通常是因为它的某个或者几个方法没有完整定义. 例如
```
abstract class Smiler(val happy: String) {
def degree: Int
}
```
* 在Scala中, 不需要对抽象方法用abstract关键字, 只是省去其方法体
* 只要类中存在抽象方法, 该类必须声明为 abstract
* 子类重写超类的抽象方法时, 不需要override关键字
```scala
class Laughter(lhappy: String) extends Smiler(lhappy) {
def degree = lhappy.hashCode
}
```
### 7.2 抽象字段
除了抽象方法外, 类还可以有抽象字段; 抽象字段就是一个没有初始值的字段. 具体的子类必须提供具体的字段; 和方法一样, 子类中重写超类的抽象字段时, 不需要`override`关键字
```scala
abstract class Abstract {
val id: Int // 没有初始化, 这是一个带有getter方法的抽象字段
var name: String // 没有初始化, 这是一个带有getter和setting方法的抽象字段
}
class AbstractField(val id: Int) extends Abstract {
var name = getClass.getName // override 可选
}
```
可以随时用匿名类型来定制抽象字段
```scala
val laught = new Abstract {
val id = 10
var name = "laught"
}
```
## 8. Scala继承层级

1. 与Java基本类型相对应的类以及Unit类型(相当于Java的void)都扩展自`AnyVal`
2. 所有其他类都是AnyRef的子类, Any是整个继承层级的根节点, AnyVal和AnyRef扩展自Any类
3. Any类定义了isInstanceOf asInstanceOf方法, 以及用于相等性判断和哈希码方法, AnyVal并没有追加方法, 只是所有值类型的一个标记
4. Null类型唯一的实例就是null, 你可以将null赋值给任何引用, 但不能赋值给值类型的变量, 举例来说不能讲Int赋值为null
5. Nothing类型没有实例, 它对于泛型结构很有用, 比如说空列表`Nil`是List[Nothing], 它是List[T]的子类型, T可以是任何类型
> Scala中的Nothing类型和Java中void不是一个概念;
> Scala中void由Unit类型表示, 该类型只有一个值, 那就是();
> 虽然Unit不是任何类型的超类, 但编译器允许任何值来替换成();
>
> def printAny(x: Any) {print(x)}
> def printUnit(x: Unit) {print(x)}
> printAny("happy")
> printUnit("happy")
## 9. 对象相等性
Scala中调用 `==`, 如果比较的是引用类型, Scala会先做`null`检查, 然后调用`equals` 方法
快学Scala之继承的更多相关文章
- 《快学Scala》
Robert Peng's Blog - https://mr-dai.github.io/ <快学Scala>Intro与第1章 - https://mr-dai.github.io/S ...
- 快学Scala 第十九课 (trait的abstract override使用)
trait的abstract override使用: 当我看到abstract override介绍的时候也是一脸懵逼,因为快学scala,只介绍了因为TimestampLogger中调用的super ...
- 快学Scala习题解答—第一章 基础
1 简介 近期对Scala比较感兴趣,买了本<快学Scala>,感觉不错.比<Programming Scala:Tackle Multi-Core Complexity on th ...
- 快学Scala 第十一课 (类继承)
类继承: class People { } class Emp extends People{ } 和Java一样,final的类不能被继承.final的字段和方法不能被override. 在Scal ...
- 快学Scala 第十八课 (trait多继承)
trait多继承: trait的继承并不像类拥有相同的含义!在下面这个例子中,如果还是运用类的继承的思想,那么运行结果将是什么也没有. trait Logged { def log(msg: Stri ...
- 《快学Scala》第八章 继承
- [Scala] 快学Scala A1L1
基础 1.1 声明值和变量 在Scala中,鼓励使用val; 不需要给出值或变量的类型,这个信息可以从初始化表达式推断出来.在必要的时候,可以指定类型. 在Scala中,仅当同一行代码中存在多条语句时 ...
- 快学Scala-第八章 继承
知识点: 1.扩展类 extends关键字,在定义中给出子类需要而超类没有的字段和方法,或者重写超类的方法. 2.重写方法 在Scala中重写一个非抽象方法必须 override 修饰符 public ...
- 《快学Scala》——控制结构和函数
条件表达式 在Scala中if/else表达式有值,这个值就是跟在if或else之后的表达式的值.例如: if (x > 0) 1 else -1 上述表达式的值是1或-1,具体是哪一个取决于x ...
随机推荐
- HourRank 19
https://www.hackerrank.com/contests/hourrank-19/challenges 第一题略. 第二题是nim博弈,问删掉一个区间的石子,使得先手败的方案有几种,明显 ...
- android 本地数据库sqlite的封装
单机android sqlite数据库的实现,这个数据库可与程序一起生成在安装包中 一.下载sqlite3.exe文件 二.运行 cmd 转到sqlite3.exe 所在目录 运行 sqlite ...
- 使用babel编译es6
起因:开发中慢慢的学习使用es6,但是JavaScript需要浏览器来解析,而不是所有浏览器都支持es6,所以为了兼容es6,需要第三方工具进行编译es6. 工具:node,gulp,gulp-bab ...
- C语言数组之冒泡排序+折半查找法(二分查找)
冒泡排序算法 将相邻的元素进行两两比较,大的向后"冒", 小的向前"赶". 口诀: N个数字来排队,两两比较小靠前 外层循环N-1(控制需要比较的轮数). 内层 ...
- Java之线程同步练习
1.有一张银行卡:*属性:name,money(账户余额)* 多线程操作同一张银行卡: 金额:x(每次存钱取钱的数额,取钱时x为负数,存钱时x为整数) 定义一个add方法:用于存取钱,参数为x,即每次 ...
- Kafka.net使用编程入门(四)
新建一个cmd窗口,zkServer命令启动zookeeper 打开另一个cmd窗口,输入: cd D:\Worksoftware\Apachekafka2.11\bin\windows kafka- ...
- a标签点击之后有个虚线边框,怎么去掉
1.行内处理方式1 <a hidefocus="true" href="#"></a> 2.行内处理方式2,让a标签获得焦点就失去焦点, ...
- MySql俩种分页区别(注意)
注意俩个分页的区别哦~ SELECT * FROM city LIMIT 2 OFFSET 1; 从第二条记录开始 取二条记录 如下: SELECT * FROM city LIMIT 3,2; 从第 ...
- 关于URL的理解
引言 URL,是统一资源定位符(Uniform Resource Locator)的缩写,一个URL就是一个特定资源在网络上的地址.理论上讲,一个URL指向一个唯一的资源,这个资源可以使一个HTML页 ...
- ActiveMQ 和消息简介
Apache ActiveMQ 是远程系统间进行通信的消息代理,实现了 JMS(Java Message Service,Java 消息服务).尽管 ActiveMQ 是使用 Java 写的,但是其提 ...