快学Scala之继承

时间:2022-10-01 10:36:14



## 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之继承的更多相关文章

  1. 《快学Scala》

    Robert Peng's Blog - https://mr-dai.github.io/ <快学Scala>Intro与第1章 - https://mr-dai.github.io/S ...

  2. 快学Scala 第十九课 (trait的abstract override使用)

    trait的abstract override使用: 当我看到abstract override介绍的时候也是一脸懵逼,因为快学scala,只介绍了因为TimestampLogger中调用的super ...

  3. 快学Scala习题解答—第一章 基础

    1 简介 近期对Scala比较感兴趣,买了本<快学Scala>,感觉不错.比<Programming Scala:Tackle Multi-Core Complexity on th ...

  4. 快学Scala 第十一课 (类继承)

    类继承: class People { } class Emp extends People{ } 和Java一样,final的类不能被继承.final的字段和方法不能被override. 在Scal ...

  5. 快学Scala 第十八课 (trait多继承)

    trait多继承: trait的继承并不像类拥有相同的含义!在下面这个例子中,如果还是运用类的继承的思想,那么运行结果将是什么也没有. trait Logged { def log(msg: Stri ...

  6. 《快学Scala》第八章 继承

  7. &lbrack;Scala&rsqb; 快学Scala A1L1

    基础 1.1 声明值和变量 在Scala中,鼓励使用val; 不需要给出值或变量的类型,这个信息可以从初始化表达式推断出来.在必要的时候,可以指定类型. 在Scala中,仅当同一行代码中存在多条语句时 ...

  8. 快学Scala-第八章 继承

    知识点: 1.扩展类 extends关键字,在定义中给出子类需要而超类没有的字段和方法,或者重写超类的方法. 2.重写方法 在Scala中重写一个非抽象方法必须 override 修饰符 public ...

  9. 《快学Scala》——控制结构和函数

    条件表达式 在Scala中if/else表达式有值,这个值就是跟在if或else之后的表达式的值.例如: if (x > 0) 1 else -1 上述表达式的值是1或-1,具体是哪一个取决于x ...

随机推荐

  1. 打通移动App开发的任督二脉、实现移动互联创业的中国梦

    年初的两会上,第一次听到克强总理讲到“互联网+”的计划,当时就让我为之感到无比振奋.我个人的理解是:“互联网+”的本质就是要对传统行业供需双方的重构,通过移动互联技术来推动各个行业上的全民创新,促使中 ...

  2. dyld&colon; lazy symbol binding failed&colon; Symbol not found&colon; &lowbar;objc&lowbar;setProperty&lowbar;nonatomic

    这个错误,一般在高版本设备里面不会出现,而在低版本会出现比如你的项目或者引入的静态库的Deployment Target设置成了ios6.0而你的测试设备是ios5.0甚至更低,就会出现如上错误.因为 ...

  3. SDL音频播放

    gcc -o tutorial03 tutorial03.c -lavutil -lavformat -lavcodec -lz -lm \`sdl-config --cflags --libs` A ...

  4. 使用ant自动编译安卓项目并签名

     准备阶段: 1.下载ant,jdk,android sdk        ant下载地址:ant.apache.org/bindownload.cgi 2. 设置环境变量      ANT_HO ...

  5. 无废话WCF入门教程四&lbrack;WCF的配置文件&rsqb;

    一.概述 配置也是WCF编程中的主要组成部分.在以往的.net应用程序中,我们会把DBConn和一些动态加载类及变量写在配置文件里.但WCF有所不同.他指定向客户端公开的服务,包括服务的地址.服务用于 ...

  6. Expression Blend4安装破解

    先在官网上下载Expression Blend4试用版 首先进入微软下载中心,http://www.microsoft.com/zh-cn/download/default.aspx: 搜索Expre ...

  7. java web 获取客户端操作系统信息

    package com.java.basic.pattern; import java.util.regex.Matcher; import java.util.regex.Pattern; /** ...

  8. Struts&plus;Spring&plus;Hibernate、MVC、HTML、JSP

    javaWeb应用 JavaWeb使用的技术,比如SSH(Struts.Spring.Hibernate).MVC.HTML.JSP等等技术,利用这些技术开发的Web应用在*项目中非常受欢迎. 先说 ...

  9. githup地址

    githup地址:https://github.com/caowenjing/test.git

  10. &lpar;原创&rpar;c&plus;&plus;11改进我们的程序之垃圾回收

    c#和java中有自动垃圾回收机制,.net运行时和java虚拟机可以管理分配的堆内存,在对象失去引用时自动回收,因此在c#和jva中, 内存管理不是大问题.c++语言没有垃圾回收机制,必须自己去释放 ...