Scala的继承和抽象类
1. 继承
1.1 语法
- Scala中使用
extends
关键字实现继承 - 可以在子类中定义父类中没有的字段和方法,或者重写父类的方法
- 类和单例对象都可以有父类
语法:
class/object A类 extends B类 { //子承父业
..
}
叫法:
A类叫子类/派生类;B类叫父类/超类/基类
1.2 类继承
方式一:非继承版
object ClassDemo{
//1.定义老师类,指定:姓名和年龄,吃饭行为
class Teacher {
var name = ""
var age = 0
def eat() = println("老师喝牛肉汤")
}
//2.定义学生类,指定:姓名和年龄,吃饭行为
class Teacher {
var name = ""
var age = 0
def eat() = println("学生吃牛肉")
}
//3.定义main方法,作为程序的主入口
def main(args: Array[String]):Unit = {
//4.测试老师类
val t = new Teacher
t.name = "刘老师"
t.age = 33
println(t.name, t.age)
t.eat()
//5.测试学生类
val s = new Student
s.name = "Lee"
s.age = 33
println(s.name, s.age)
s.eat()
}
}
方式二:继承版
object ClassDemo{
//1.定义Person类,作为父类
class Person {
//2.定义公共的内容:姓名、年龄、吃饭
var name = ""
var age = 0
def eat() = println("人要吃饭")
}
//3.定义老师类,继承人类
class Teacher extends Person{}
//4.定义学生类,继承人类
class Student extends Person{}
//5.定义main方法,作为程序的主入口
def main(args: Array[String]):Unit = {
//6.测试老师类
val t = new Teacher
t.name = "刘老师"
t.age = 33
println(t.name, t.age)
t.eat()
//7.测试学生类
val s = new Student
s.name = "Lee"
s.age = 33
println(s.name, s.age)
s.eat()
}
}
//(刘老师,33)
//人要吃饭
//(Lee,33)
//人要吃饭
1.3 单例对象继承
Scala中,单例对象也是可以继承类的。
object ClassDemo{
//1.定义Person类,作为父类
class Person {
var name = ""
def sayHello() = println("hi")
}
//2.定义单例对象Student,继承Person
object Student extends Person {}
//3.定义main方法,作为程序的主入口
def main(args: Array[String]):Unit = {
//4.测试Student中的成员
Student.name = "Lee"
println(Stundet.name)
Student.sayHello()
}
}
//Lee
//hi
1.4 方法重写
Scala可以在子类中使用override
来重写父类的成员,也可以使用super
来引用父类的成员
注意:
父类用var
修饰的变量,子类不能重写
示例:
object ClassDemo{
//1.定义Person类,作为父类
class Person {
//成员变量
val name = "Lee" //val修饰的变量,值不能被修改
var age = 23 //var修饰的变量,值可以被修改
//成员方法
def sayHello() = println("hi")
}
//2.定义Student类,继承Person
class Student extends Person {
//重写父类的成员变量
override val name = "Mike"
//override var age = 30 //报错,因为父类用var修饰的变量,子类不能重写
//重写父类的成员方法
override def sayHello() = {
super.sayHello()
println("yoyo")
}
}
//3.定义main方法,作为程序的主入口
def main(args: Array[String]):Unit = {
//4.测试
val s = new Student
println(s.name, s.age)
s.sayHello()
}
}
//(Mike,23)
//hi
//yoyo
2. 类型判断
2.1 isinstanceOf和asinstanceOf
- isinstanceOf: 判断对象是否为指定类的对象
- asinstanceOf: 将对象转换为指定类型
格式:
//判断对象是否为指定类的对象
val trueOrFlase: Boolean = 对象.inInstanceOf[类型]
//将对象转换为指定类型
val 变量 = 对象.asInstanceOf[类型]
示例:
object ClassDemo{
//1.定义Person类
class Person
//2.定义Student类,继承Person
class Student extends Person {
override def sayHello() = println("hi")
}
//3.定义main方法,作为程序的主入口
def main(args: Array[String]):Unit = {
//4.通过多态的形式,创建Student类型的对象
/*多态
概述:同一个事物在不同时刻表现出来的不同形态
弊端:父类引用不能直接使用子类的特有成员
*/
val p:Person = new Student //多态
println(s.name, s.age)
s.sayHello()
//5.尝试调用Student类中的sayHello()方法
//p.sayHello() //报错,父类引用不能直接使用子类的特有成员
//6.解决方案
//6.1判断对象p是否是Student类型的对象
if(p.isInstanceOf[Student]){
//6.2如果是,就将其转换成Student类型的对象,然后调用sayHello()方法即可
val s = p.asInstanceOf[Student]
//上边这行代码相当于:val s:Student = new Student
s.sayHello()
}
}
}
//hi
2.2 getClass和classOf
isInstanceOf只能判断对象是否为指定类及其子类的对象,但如果要求精准判断出对象的类型就是指定的数据类型,就只能使用getClass和classOf来实现
- p.getClass可以精准获取对象的类型
- classOf[类名]可以精准获取数据类型
- 使用==操作符可以直接比较类型
示例:
object ClassDemo{
//1.定义Person类
class Person
//2.定义Student类,继承Person
class Student extends Person
//3.定义main方法,作为程序的主入口
def main(args: Array[String]):Unit = {
//4.通过多态的形式,创建Student类型的对象
val p:Person = new Student //多态
//5.通过isInstanceOf关键字来判断创建的对象是否是Person类型的对象
println(p.isInstanecOf[Person]) //只要传入Person类型或其子类对象,返回值都是true
//6.通过isInstanceOf关键字来判断创建的对象是否是Student类型的对象
println(p.isInstanecOf[Student]) //只要传入Student类型或其子类对象,返回值都是true
//7.通过getClass和classOf关键字来判断创建的对象是否是Person类型的对象
println(p.getClass == classOf[Person]) //传入的必须是Person类型的对象,否则返回false
//8.通过getClass和classOf关键字来判断创建的对象是否是Student类型的对象
println(p.getClass == classOf[Student]) //传入的必须是Student类型的对象,否则返回false
}
}
//true
//true
//false
//true
3. 抽象类
Scala是支持抽象类的,通过abstract
关键字实现
抽象类:类中有抽象字段或抽象方法
- 抽象字段:没有初始化值的变量
- 抽象方法:没有方法体的方法
格式:
//定义抽象类
abstract class 抽象类名 {
//定义抽象字段
val/var 抽象字段名:类型
//定义抽象方法
def 方法名(参数:参数类型,参数:参数类型...):返回类型
}
注意:
抽象类的子类:
1.如果也是抽象类,则不用重写父类的抽象方法
2.如果是普通类,则必须重写父类所有的抽象方法
示例1:
object ClassDemo{
//1.定义Shape抽象类,添加一个area抽象方法
abstract class Shape{
def area():Double //抽象方法
}
//2.定义Square类,继承Shape,它有一个边长的主构造器,能实现计算面积的方法
class Square(var edge:Double) extends Shape {
override def area(): Double = edge * edge
}
//3.定义Rectangle类,继承Shape,它有一个长、宽的主构造器,能实现计算面积的方法
class Rectangle(var length:Double, var width: Double) extends Shape {
override def area(): Double = length * width
}
//4.定义Circle类,继承Shape,它有一个半径的主构造器,能实现计算面积的方法
class Circle(var radius:Double) extends Shape {
override def area(): Double = Math.PI * radius * radius
}
//5.定义main方法,作为程序的主入口
def main(args: Array[String]):Unit = {
//6.测试
val s1 = new Square(5)
println(s"s1: ${s1.area()}")
val s2 = new Rectangle(4, 3)
println(s"s2: ${s2.area()}")
val s3 = new Circle(3)
println(s"s3: ${s3.area()}")
}
}
//s1: 25.0
//s2: 12.0
//s3: 28.27433882308138
示例2:
object ClassDemo{
//1.定义Person抽象类,它有一个String抽象字段occupation
abstract class Shape{
val occupation:String //抽象字段
}
//2.定义Student类,继承Person,重写occupation字段,初始化为学生
class Student extends Person {
override val occupation: String = "学生"
}
//3.定义Teacher类,继承Person,重写occupation字段,初始化为老师
class Teacher extends Person {
override val occupation: String = "老师"
}
//5.定义main方法,作为程序的主入口
def main(args: Array[String]):Unit = {
//6.测试
val t = new Teacher
println(t.occupation)
val s = new Student
println(s.occupation)
}
}
//老师
//学生
4.匿名内部类
匿名内部类是继承了类的匿名的子类对象,它可以直接用来创建实例对象。Spark的源代码中大量使用到匿名内部类,因此对我们查看Spark底层源码十分有帮助。
语法:
new 类名() {
//重写类中所有的抽象内容
}
注意:
上述格式中,如果类的主构造器参数列表为空,则小括号可以省略不写。
使用场景:
- 当对对象方法(成员方法)仅调用一次的时候
- 可以作为方法的参数进行传递
示例:
object ClassDemo{
//1.定义Person抽象类,并添加一个sayHello抽象方法
abstract class Person {
def sayHello() //抽象方法
}
//2.定义一个show()方法,该方法需传入一个Person类型的对象,然后调用Person类中的sayHello()方法
def show(p:Person) = p.sayHello()
//3.定义main方法,作为程序的主入口
def main(args: Array[String]):Unit = {
//需求:调用Person类中的sayHello()方法
//演示的是使用场景1
new Person() {
override def sayHello():Unit = println("hi")
}.sayHello()
//4.调用show()方法
//show(这里传入一个Person类型的对象)
//通过匿名内部类的形式创建Person抽象类的子类对象
//演示的是使用场景2
val p:Person = new Person() { //多态
override def sayHello() = println('Hello')
}
show(p)
}
}
//hi
//hello
5. 案例:动物类
需求:
步骤:
object ClassDemo{
//1.定义Animal抽象类,属性:姓名,年龄,行为:跑步,吃饭
abstract class Animal {
var name = ""
var age = 0
def run() = println('动物会跑步')
def ear() //抽象方法
}
//2.定义Cat类,继承Animal,重写吃饭的方法,并定义该类独有的抓老鼠的方法
class Cat extends Animal {
override def eat(): Unit = println("猫吃鱼")
def catchMouse() = println("猫抓老鼠")
}
//3.定义Dog类,继承Animal,重写吃饭的方法,并定义该类独有的看家的方法
class Dog extends Animal {
override def eat(): Unit = println("狗吃肉")
def lookHome() = println("狗看家")
}
//4.定义main方法,作为程序的主入口
def main(args: Array[String]):Unit = {
//5.测试猫类
//5.1创建猫类对象
val c:Animal = new Cat
//5.2给成员变量赋值
c.name = "加菲猫"
c.age = 13
//5.3打印成员变量值
println(c.name, c.age)
//5.4调用从父类继承过来的方法:run(),eat()
c.run()
c.eat()
//5.5调用猫类独有的抓老鼠功能
//c.catchMouse()
if(c.isInstanceOf[Cat]) {
//c是猫类对象
val c2 = c.asInstanceOf[Cat]
c2.catchMouse()
} else {
//c不是猫类对象
println("传入的不是猫类对象")
}
}
}
//(加菲猫, 13)
//动物会跑步
//猫吃鱼
//猫抓老鼠