一.概念
- 定义:在原有类的基础上定义一个新类,原有类称为父类,新类称为子类。 class 子类名 extends 父类名 { 类体 }
- 好处:复用代码和实现多态。复用代码:子类可以继承父类的特性。多态 : 子类可以在自己内部实现父类没有的特性。
object class12 {
// 伴生类
class Boss {
def power(): Unit = {
println("Boss 有权利.....")
}
var car = "豪车"
}
// 子类 继承 父类
class NoBody extends Boss {
}
def main(args:Array[String]): Unit = {
val b = new NoBody()
println(b.car)
b.power()
}
}
二.重写
- 概念:子类对父类的同名方法进行重写
- 当子类从父类继承的方法不能满足需要时,子类需要有自己的行为,怎么办?此时使用使用 override 可以重写父类的方法。
class Boss {
def power(): Unit = {
println("Boss 有权利.....")
}
var car = "豪车"
}
// 子类 继承 父类
class NoBody extends Boss {
def run():Unit = {
}
override def power(): Unit = {
println("老莫,我想吃鱼了")
}
}
def main(args:Array[String]): Unit = {
val b = new NoBody()
println(b.car)
b.power()
}
三.构造器
- 构造器的调用顺序:先调用父类的构造器,再调用子类的构造器
object class14 {
class Father() {
println("Father 构造器被调用")
}
class Son extends Father(){
println("Son 构造器被调用")
}
def main(args:Array[String]): Unit = {
//new Father()
new Son()
}
}
三-1.带参构造器
- 子类带参构造器:继承父类的属性。不用写val,var修饰符/自己的新属性,加上var,val修饰符
- 父类构造器:直接传入参数,不用写属性的类型
object class15 {
class Dog(var name:String, var age:Int) {
println(s"Dog ${name}, ${age} 构造器被调用")
}
class RuralDog(name:String,age:Int) extends Dog(name,age){
println("RuralDog的构造器.....")
}
def main(args:Array[String]): Unit = {
new RuralDog("旺财", 3)
}
class Dog(var name:String, var age:Int) {
println(s"Dog ${name}, ${age} 构造器被调用")
}
class RuralDog(name:String,age:Int,var color:String) extends Dog(name,age){
println("RuralDog的构造器.....")
}
def main(args:Array[String]): Unit = {
new RuralDog("旺财", 3,"土黄色")
}
}
题
你正在设计一个二维游戏的界面,需要用很多的点来表示游戏中的角色。 设计一个Point类,其x和y可以通过构造器提供。 它有几个方法:
- 方法1: 计算自己在哪个象限。 whereAmI():String
- 2.方法2: 计算和坐标原点的距离。getDist():Double
- 3.方法3: 计算与另一个点的距离。fromPoint(other:Point):Double
- 4.方法4: 重写equals 判断是否是同一个点(x和y都相等就是同一个点)。
- 5.方法5: 重写toString,更友好的输出点的信息。 再设计一个子类LabelPoint它来继承Point类,其构造器接收一个标签值和x,y坐标。 例如: New LabelPoint("black",1,2)
// 二维游戏点坐标类(基础父类)
class Point(val x: Double, val y: Double) {
// 方法1:判断当前点所在象限(游戏中可用于区域划分、阵营判定等)
def whereAmI(): String = {
(x, y) match {
case (0.0, 0.0) => "原点(无象限)"
case (x, y) if x > 0 && y > 0 => "第一象限"
case (x, y) if x < 0 && y > 0 => "第二象限"
case (x, y) if x < 0 && y < 0 => "第三象限"
case (x, y) if x > 0 && y < 0 => "第四象限"
case (0.0, _) => "x轴上(无象限)"
case (_, 0.0) => "y轴上(无象限)"
}
}
// 方法2:计算到坐标原点的距离(游戏中可用于判定角色是否在技能范围、安全区等)
def getDist(): Double = {
math.sqrt(x * x + y * y)
}
// 方法3:计算与另一个点的距离(游戏中可用于角色间距判定、攻击范围检测等)
def fromPoint(other: Point): Double = {
val dx = x - other.x // 横向距离差
val dy = y - other.y // 纵向距离差
math.sqrt(dx * dx + dy * dy) // 欧氏距离公式
}
// 方法4:重写equals,坐标完全相同则判定为同一点(游戏中可用于判定是否重叠、碰撞等)
override def equals(obj: Any): Boolean = {
obj match {
case other: Point => x == other.x && y == other.y // 仅比较坐标(忽略其他可能的扩展属性)
case _ => false // 非Point类型直接返回不相等
}
}
// 方法5:重写toString,友好输出点信息(游戏调试时便于查看坐标)
override def toString(): String = {
s"Point(坐标: ($x, $y), 象限: ${whereAmI()}, 到原点距离: ${getDist().formatted("%.2f")})"
}
// 可选:重写hashCode(与equals配套,避免集合中判重异常)
override def hashCode(): Int = {
val prime = 31
var result = 1
result = prime * result + x.hashCode()
result = prime * result + y.hashCode()
result
}
}
// 带标签的游戏点类(子类,用于区分不同角色/物体,如"玩家"、"敌人"、"道具"等)
class LabelPoint(val label: String, x: Double, y: Double) extends Point(x, y) {
// 重写toString,增加标签信息(游戏中便于区分不同类型的点)
override def toString(): String = {
s"LabelPoint(标签: $label, 坐标: ($x, $y), 象限: ${whereAmI()}, 到原点距离: ${getDist().formatted("%.2f")})"
}
// 可选:扩展方法 - 判定当前点是否与同标签的点重叠(游戏中可用于同类型角色碰撞检测)
def isSameLabelOverlap(other: LabelPoint): Boolean = {
this.label == other.label && this.equals(other)
}
}
// 游戏场景测试代码(验证功能可用性)
object GamePointTest {
def main(args: Array[String]): Unit = {
// 1. 测试基础Point类
val playerPos = new Point(3.0, 4.0) // 玩家坐标
val enemyPos = new Point(-2.0, 5.0) // 敌人坐标
val origin = new Point(0.0, 0.0) // 原点(比如出生点)
println("=== 基础Point类测试 ===")
println(playerPos) // 测试toString
println(s"玩家与敌人的距离:${playerPos.fromPoint(enemyPos).formatted("%.2f")}") // 测试两点距离
println(s"敌人是否在原点:${enemyPos.equals(origin)}") // 测试equals
println(s"原点信息:$origin") // 测试原点的象限判定
// 2. 测试LabelPoint子类
val player = new LabelPoint("玩家A", 3.0, 4.0)
val enemy = new LabelPoint("敌人B", -2.0, 5.0)
val item = new LabelPoint("金币", 3.0, 4.0) // 与玩家同坐标的道具
println("\n=== LabelPoint子类测试 ===")
println(player) // 测试子类toString
println(enemy)
println(item)
println(s"玩家与金币是否同标签重叠:${player.isSameLabelOverlap(item)}") // 测试扩展方法
println(s"玩家与金币坐标是否相同:${player.equals(item)}") // 继承父类equals方法
println(s"敌人到玩家的距离:${enemy.fromPoint(player).formatted("%.2f")}") // 继承父类距离方法
}
}