Scala学习八——继承
一.本章要点
- extends,final关键字和Java一样
- 重写方法时必须使用override
- 只有主构造器可以调用超类的构造器
- 可以重写字段
二.扩展类
Scala扩展类和Java一样(使用extends关键字),也可以将类声明为final让它不能被扩展,也可以将单个方法或字段声明为final,确保不能重写。
注:Java中final是不可变的(相当于Scala中的val),但是Scala中是不能被扩展
三.重写方法
使用override修饰符:
public class Person{
override def toString=....
}
override的作用在多个常见情况下给出有用的错误提示,如:
- 拼错重写的方法名
- 在新方法中使用了错误的参数类型
- 在超类中引用新的方法,但是这个方法与子类方法相抵触(易违约基类问题,超类的修改无法在不检查所有子类的前提下被验证)
在Scala中调用超类的方法和Java完全一样,使用super关键字
四.类型检查和转换
isInstanceOf:测试某个对象是否属于某个给定的类,可以用isInstanceOf方法,如果为true就可以用asInstanceOf方法将引用转换为子类的引用。
例:
//如果p指向的是Employee类及其子类(比如Manager)的对象,则p.isInstanceOf[Employee]将会成功。
//如果p是null,则p.isInstanceOf[Employee]返回false,p.asInstanceOf[Employee]将返回null
//如果p不是一个Employee,则p.asInstanceOf[Employee]将抛出异常
if(p.isInstanceOf[Employee]){
val s=p.asInstanceOf[Employee] }
classOf(在scala.Predef中,可以自动导入):测试某个对象是某个类的对象但又不是其子类。
例:
if(p.getClass==classOf[Employee])
五.受保护字段和方法
将字段或方法声明为protected,这样的成员可以被任何子类访问,但不能从其他位置看到。
注:与Java不同,protected的成员对于类所属的包而言,是不可见的;
Scala还停工了protected[this]的变体,把访问权限限定在当前的对象
六.超类的构造
辅助构造器永远不可能直接调用超类的构造器,子类的辅助构造器最终都会调用主构造器,只有主构造器可以调用超类的构造器。
主类构造器和类定义交织在一起,调用超类构造器也是交织在一起。
例:
//Employee类的三个参数有两个传递给了超类
class employee(name:String,age:Int,val salary:Double) extends Person(name,age)
注:在Scala构造器中,不能调用super(params)[Java可以]
Scala可以扩展Java类,这种情况必须调用Java类的某一个构造方法
七.重写字段
子类可以重写父类的字段。
注:
- def只能重写另一个def
- val只能重写另一个val或不带参数的def
- val只能重写另一个抽象的var
八.匿名子类
和Java一样,可以通过包含带有定义或重写代码块的方式创建一个匿名的子类,例:
//这会创建一个结构类型的对象,可以作为参数类型的定义
val alien=new Person("Fred"){ def greeting="xxxxxxx" } def meet(p:Person(def greeting:String)){}
九.抽象类
和Java一样,可以用abstract关键字标记不能被实例化的类(通常因为某个或某几个方法没有被完整定义)。
例:
abstract class Employee(val name:String){
def id:Int //没有方法体——抽象方法
}
注:
Scala中抽象方法不用使用abstract关键字,只需省略方法体就行;
只要类中有一个抽象方法,这个类就需要是抽象类,类必须声明abstract;
子类中重写超类的抽象方法时不需要使用override关键字
十.抽象字段
即没有初始值的字段。
例:
abstract class Person{
val id:Int //没有初始化——带有抽象的getter方法的抽象字段
var name:String //带有抽象的getter和setter方法 }
注:子类必须提供具体的字段;
子类重写超类的字段不需要使用override
//具体的id和name属性
class Employee(var id:Int) extends Person{
var name="" }
//通过匿名类型定制抽象字段
val fred=new Person{ val id=1
val name="Fred"
}
十一.构造顺序和提前定义
在子类中重写val并且在超类中的构造器使用该值有可能出现问题(因为超类的构造器先于子类的构造器运行,根本原因来自Java语言的设定——允许在超类的构造方法中调用子类的方法),如:
class Creature{
val range:Int=10
val env:Array[Int] = new Array[Int](range) } class Ant extends Creature{
override val range=2 }
......
//长度为0
val ant=new Ant
println(ant.env.length)
/××
过程如下:
1.Ant的构造器在构造自己之前先调用Creature的构造器;
2.Creature的构造器把它的range设为10;
3.Creature的构造器为了初始化env数组,调用range()取值器;
4.该方法被重写以输出(还未初始化)Ant类的range字段值;
5.range方法返回0(这是对象被分配空间时所有整型字段的初始值);
6.env被设为长度为0的数组;
7.Ant构造器继续执行,将其range设为2
××/
注:因此构造器内不应该依赖val的值;
解决方式:
1.将val声明为final,这样很安全但并不灵活;
2.在超类中将val声明为lazy,这样很安全但不高效;
3.在子类中使用提前定义方法(可以在超类的构造器执行之前初始化子类的val字段),使用with关键字(提前定义的等号右侧只能引用之前已有的提前定义,而不能使用类中的其他字段或方法)
class Ant extends{
override val range=2 }with Creature
可以使用-Xcheckinit编译器标志调式构造顺序
十二.Scala继承等级
Scala继承等级
注:
AnyRef是Java或.Net虚拟机Object类的同义词;
AnyVal和AnyRef都扩展于Any类,而Any类是整个继承等级的根节点;
Any类中定义了isInstanceOf,asInstanceOf方法,相等性判断,哈希码的方法;
AnyVal没有追加任何方法,他只是一个标记;
AnyRef追加了来自Object类的监视方法wait和notify/notifyAll,同时提供了synchronized方法;
所有Scala类都实现ScalaObject这个标记接口,该接口没有任何方法;
Null值的唯一实例是null;
Nothing类型没有实例
十三.对象相等性
Scala中AnyRef的eq方法检查两个引用是否指向同一个对象,AnyRef的equals方法调用eq。
实现类的时候有需要时重写equals根据自己的逻辑判断,例:
注:将方法定义为final,因为通常而言在子类中正确扩展相等性判断非常困难;
确保定义的equals方法参数类型为Any ;
再定义equals时,记得同时定义hashCode
final override def equals(other:Any){ val that=other.asInstanceOf(Item)
if(that==null) false
else description==that.description&&price==that.price
}
十四.练习
Scala学习八——继承的更多相关文章
- Scala学习(八)---Scala继承
Scala继承 摘要: 在本篇中,你将了解到Scala的继承与Java和C++最显著的不同.要点包括: 1. extends.final关键字和Java中相同 2. 重写方法时必须用override ...
- Scala学习(八)练习
Scala中继承&练习 1. 扩展如下的BankAccount类,新类CheckingAccount对每次存款和取款都收取1美元的手续费 class BankAccount ( initial ...
- JavaScript之面向对象学习八(继承)
简介:继承是OO语言中的一个最为人津津乐道的概念.许多OO语言都支持两种继承方式:接口继承和实现继承.接口继承只继承方法签名,而实现继承则继承实际的方法. 但是JS的函数并没有签名,所以在ECMASc ...
- scala学习笔记2(类,继承,抽象类)
class Person{ // _ 是占位符; var name : String = _ val age : Int = 27 // private[this] 定义的内容无法外部使用,起到保护作 ...
- (C/C++学习笔记) 十八. 继承和多态
十八. 继承和多态 ● 继承的概念 继承(inheritance): 以旧类为基础创建新类, 新类包含了旧类的数据成员和成员函数(除了构造函数和析构函数), 并且可以派生类中定义新成员. 形式: cl ...
- Scala 学习之路(九)—— 继承和特质
一.继承 1.1 Scala中的继承结构 Scala中继承关系如下图: Any是整个继承关系的根节点: AnyRef包含Scala Classes和Java Classes,等价于Java中的java ...
- 【Todo】【读书笔记】大数据Spark企业级实战版 & Scala学习
下了这本<大数据Spark企业级实战版>, 另外还有一本<Spark大数据处理:技术.应用与性能优化(全)> 先看前一篇. 根据书里的前言里面,对于阅读顺序的建议.先看最后的S ...
- Python Tutorial 学习(八)--Errors and Exceptions
Python Tutorial 学习(八)--Errors and Exceptions恢复 Errors and Exceptions 错误与异常 此前,我们还没有开始着眼于错误信息.不过如果你是一 ...
- 【大数据】Scala学习笔记
第 1 章 scala的概述1 1.1 学习sdala的原因 1 1.2 Scala语言诞生小故事 1 1.3 Scala 和 Java 以及 jvm 的关系分析图 2 1.4 Scala语言的特点 ...
随机推荐
- 19.顺时针打印矩阵 Java
题目描述 输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下4 X 4矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则依次打印出数 ...
- Leetcode题目198.打家劫舍(动态规划-简单)
题目描述: 你是一个专业的小偷,计划偷窃沿街的房屋.每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警. 给 ...
- JS基础_call和apply
call()和apply() - 这两个方法都是函数对象的方法,需要通过函数对象来调用 - 当对函数调用call()和apply()都会调用函数执行 - 在调用call和apply可以将一个对象指定为 ...
- Qt事件机制浅析
Qt事件机制 Qt程序是事件驱动的, 程序的每个动作都是由幕后某个事件所触发.. Qt事件的发生和处理成为程序运行的主线,存在于程序整个生命周期. Qt事件的类型很多, 常见的qt的事件如下: 键盘事 ...
- Reflexil
https://github.com/sailro/Reflexil/issues/47 Instructions on how to install Reflexil would be much a ...
- java的JDBC驱动使用链接数据库
1. import java.sql.*; 2 . 导入所需要的数据库的jar包,如oracle/informix的 3. String sql = "select * from ...
- 小D课堂 - 新版本微服务springcloud+Docker教程_6-04 自定义Zuul过滤器实现登录
笔记 4.自定义Zuul过滤器实现登录鉴权实战 简介:自定义Zuul过滤器实现登录鉴权实战 1.新建一个filter包 2.新建一个类,实现ZuulFilter,重写里面的方法 3.在类顶部加 ...
- c++ STL之map
map内部自建一颗红黑树(一 种非严格意义上的平衡二叉树),这颗树具有对数据自动排序的功能,所以在map内部所有的数据都是有序的,map中的元素是自动按Key升序排序,所以不能对map用sort函数: ...
- grep 正则表达式用引号括起来和元字符加反斜杠转义的测试
grep 正则表达式用引号括起来和元字符加反斜杠转义的测试 实验在 grep 命令中的表达式:不加引号,加单引号,加双引号的区别,以及部分元字符前加与不加 `\’ 进行转义的区别.实验环境为“实验楼( ...
- 【C# in depth 第三版】温故而知新(1) (转)
声明 本文欢迎转载,原文地址:http://www.cnblogs.com/DjlNet/p/7192354.html 前言 关于这本书(<深入理解C# 第三版>)的详细情况以及好坏,自行 ...