当前位置: 首页 > article >正文

[读书日志]从零开始学习Chisel 第五篇:Scala面向对象编程——类继承(敏捷硬件开发语言Chisel与数字系统设计)

3.3类继承
3.3.1Scala中的类继承

为了节省代码量和反映实际各种类之间的联系,通常采取两种策略,包含和继承。包含是说明一个类中包含另一个类的对象,但两者之间没有必然联系。继承是从一个宽泛的类派生出更具体的类的过程,

被继承的类称为“超类”或“父类”,而派生出来的类称为“子类”,如果继承层次较深,最顶层的类通常也叫“基类”。通过在类的参数列表后面加上关键字extends和被继承类的类名,就完成了继承的过程。

scala> class A {
     | val a = "Class A"
     | }
// defined class A

scala> class B extends A {
     | val b = "Class B inherits from A"
     | }
// defined class B

scala> val x = new B
val x: B = B@611587f7

scala> x.a
val res0: String = Class A

scala> x.b
val res1: String = Class B inherits from A
3.3.2调用超类的构造方法

在以上的例子中,A没有参数,当A有参数时B应该如何调用呢?在构造某个类的对象时,应该先构建超类对象的组件,再构造子类的其他组件。也就是说,类B应当调用类A的构造方法。语法是:

class 子类(子类对外接收的参数) extends 超类(子类给超类的参数)

Scala只允许主构造方法调用超类的构造方法。示例如下:

scala> class A(val a: Int)
// defined class A

scala> class B(giveA:Int, val b : Int) extends A(giveA)
// defined class B

scala> val x = new B(10,20)
val x: B = B@7fd3fd06

scala> x.a
val res2: Int = 10

scala> x.b
val res3: Int = 20

scala> x.giveA
-- [E173] Reference Error: ---------------------------------------------------------------------------------------------
1 |x.giveA
  |^^^^^^^
  |value giveA cannot be accessed as a member of (x : B) from object rs$line$15.
  |  private value giveA can only be accessed from class B.
1 error found
3.3.3重写超类的成员

不被继承的成员

一般情况下,超类的成员都会被子类继承,但有两种不会被继承,一是超类中用private修饰的私有成员,二是被子类重写的成员。重写超类的成员时,应该再定义的开头加上关键字override。之前的toString函数就是使用这种方法重写的。

不可重写的成员

如果超类成员在开头用关键字final修饰,则子类只能继承,不能重写。使用final修饰class,则这个类禁止被其他类继承。

无参方法与字段

无参方法在调用时可以省略空括号,因此对于用户代码而言,调用无参方法和调用同名字段没有什么不同,Scala允许超类的无参方法被子类重写为字段,但是字段不能反过来被重写为方法,而且方法返回的类型必须与字段的类型一致。

字段与方法的区别在于,字段一旦被初始化,就会被保存在内存中,以后每次调用都只需要读取内存,而方法不会占用内存空间,但每次调用都需要执行一遍程序段,速度更慢。

Scala只有两种命名空间,值——字段、方法、包、单例对象;类型——类、特质

因为字段和方法同处一个命名空间,所以字段可以重写无参方法。在同一个域中不允许同时出现同名的字段、无参方法和单例对象。

3.3.4子类型多态与动态绑定

类型为超类的变量可以指向子类的对象,称为子类型多态。但是对于方法而言,尽管变量的类型是超类,但方法的版本是动态绑定的。调用的方法要允许哪个版本,是由变量指向的对象来决定的。

scala> class A {
     | def display() = "I'm A."
     | }
// defined class A

scala> class B extends A {
     | override def display() = "I'm B."
     | }
// defined class B

scala> val x: A = new B
val x: A = B@1fd35a92

scala> x.display()
val res4: String = I'm B.

上面的程序中,声明了一个类型为A的变量,创建B的对象赋值给它,它调用方法时调用的是B类的方法。

3.3.5抽象类

如果类中包含没有初始化的字段或没有函数体的方法,那么这个类是抽象类,必须用abstract修饰。抽象类无法通过new来构造实例对象。抽象类确实的成员定义,可以由抽象类的子类补充,即抽象类声明了抽象成员,但没有定义。如果子类补全了相关定义,称子类“实现”了超类的抽象成员。此时override可写可不写。

scala> abstract class A {
     | val a: Int
     | }
// defined class A

scala> class B(val b: Int) extends A {
     | val a = b * 2
     | }
// defined class B

scala> val y = new B(1)
val y: B = B@58486deb

scala> y.a
val res5: Int = 2

scala> y.b
val res6: Int = 1

抽象类常用于定义基类,基类会派生出很多不同的子类,基类只需要声明公共成员,让子类实现它们各自期望的版本。

3.3.6多重继承

Scala没有多重继承,这让一些特性变得非常简洁。Scala设计了“特质”来实现相同的功能,并且它的规则更加简单明了。

3.3.7Scala类的层次结构

Scala所有的类,包括已有的类和自定义的类,都不是毫无关联的,如下图所示,箭头表示属于指向的类的子类:
在这里插入图片描述
最顶部的是抽象类Any,它是所有类的超类。
在这里插入图片描述
Any有两个子类,即AnyValAnyRef,所有类被分为两大部分,值类和引用类。值类之间存在隐式转换,就是从Byte到Doubel的转换。除了9个值类,也可以自定义值类,但必须显式继承自AnyVal,否则都认为是AnyRef的子类。

另外,Nothing是所有类的子类,表示空值或空引用。Null类是空引用,Scala中可以把各种类型打包成一个特殊的可选值,为了表示空,没有这个特殊的概念,以及兼容各种自定义、非自定义的值和引用类,所以这个特殊的可选值就是把Nothing类进行打包。


http://www.kler.cn/a/472385.html

相关文章:

  • js es6 reduce函数, 通过规格生成sku
  • 【C语言】_指针与数组
  • Matlab回归预测大合集(不定期更新)-188
  • node.js内置模块之---buffer 模块
  • PixPin—— 高效截图工具的下载与使用攻略
  • 如何安全保存用户密码及哈希算法
  • 浅尝Appium自动化框架
  • 计算机网络 (30)多协议标签交换MPLS
  • PL/SQL语言的正则表达式
  • 论文阅读 - 模拟误导信息易感性 (SMISTS): 利用大型语言模型模拟加强误导信息研究
  • 大模型思维链推理的进展、前沿和未来分析
  • C++:字符数组
  • SQL—替换字符串—replace函数用法详解
  • ffmpeg7.0 合并2个 aac 文件
  • 使用 MongoDB 构建高效的 NoSQL 数据库
  • ChatGPT如何赋能办公
  • 以太网MAC和PHY层问题的“对症下药”攻略
  • 缓存-Redis-API-Redission-可重入锁-原理
  • IWOA-GRU和GRU时间序列预测(改进的鲸鱼算法优化门控循环单元)
  • Centos7 安装MySQl8.0报错:“MySQL 8.0 Community Server“ 的 GPG 密钥已安装,但是不适用于此软件包