快学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继承层级
![](http://images2015.cnblogs.com/blog/1182370/201707/1182370-20170710195416509-461234798.png)
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 ...
随机推荐
- 如何在Elasticsearch中安装中文分词器(IK)和拼音分词器?
声明:我使用的Elasticsearch的版本是5.4.0,安装分词器前请先安装maven 一:安装maven https://github.com/apache/maven 说明: 安装maven需 ...
- javaWeb学习总结(7)-关于session的实现:cookie与url重写
本文讨论的语境是java EE servlet.我们都知道session的实现主要两种方式:cookie与url重写,而cookie是首选(默认)的方式,因为各种现代浏览器都默认开通cookie功能, ...
- REDIS安装与配置
1. mkdir /home/redis/ 2. mkdir /home/redis/conf 3. mkdir /home/redis/data 4. cd /home 5. 下载redis版本3. ...
- JMETER 不同线程组 变量值 的参数传递
线程组 1 在线程组1中使用__setProperty函数设置jmeter属性值(此值为全局变量值),将所需变量值如${token}设置为jmeter属性值,即newtoken,示例: 1.添加- ...
- AngularJS入门第一课
1.ng-app=" " 定义angularJS的使用范围: 2.ng-init="变量=值;变量='值'" 初始化变量的值,有多个变量时,中间用分号隔 ...
- 剖析WPF数据绑定机制
引言 WPF框架采取的是MVVM模式,也就是数据驱动UI,UI控件(Controls)被严格地限制在表示层内,不会参与业务逻辑的处理,只是通过数据绑定(Data Binding)简单忠实地表达与之绑定 ...
- JS阻塞以及CSS阻塞
一.JS阻塞 所有的浏览器在下载JS文件的时候,会阻塞页面上的其他活动,包括其他资源的下载以及页面内容的呈现等等,只有当JS下载.解析.执行完,才会进行后面的 操作.在现代的浏览器中CSS资源和图片i ...
- ios开发 oc 的类方法与对象方法
--------开始前先申明一下:小编为了让大家看出效果,在编码中命名方式会又些不规范. 首先我们先来了解一下什么是类方法与对象方法. 对象方法: 对象是由“-”开头.比如:-(void)Runner ...
- MYSQL更改root password时遇到Access Denied的解决办法
今天在公司虚拟机上装MYSQL之后需要修改root password,然而遇到这样的错误: Access denied for user 'root'@'localhost' (using passw ...
- ionic 项目中创建侧边栏的具体流程分4步简单学会
这是在学习ionic时,当时遇到的一些问题,觉得很难,就记笔记下来了,现在觉得如果可以拿来分享,有可能会帮助到遇到同样问题的人 ionic slidemenu 项目流程: cd pretices(自己 ...