七、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)
//动物会跑步
//猫吃鱼
//猫抓老鼠
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值