scala 类的继承

73 阅读2分钟

前面我们学习了Scala中类的相关知识,主要是一个类和一个对象,接下来今天先来学习两个类之间的继承关系。

继承的定义

在原有类的基础上定义一个新类,原有类称为父类,新类称为子类。

子类可以直接使用父类的属性和方法

子类可以在自己内部实现父类没有的特性。

class 子类名 extends 父类名 { 类体 }

案例

object class09 {

  class Animal() {
  def eat():Unit = {
    println("animal eat...")
  }
}

  class Dog() extends Animal() { 
  } //Dog就直接具备了animal的功能eat
  
  def main(args: Array[String]): Unit = {
    val d1 = new Dog()
    d1.eat()   // animal eat...
  }
}

继承的方法重写

如果希望对父类的方法进行改进,使用 override 可以重写父类的方法。

案例

object class10 {
  class Parent() {
    def run(): Unit = {
      println("run...")
    }
  }
  class Son extends Parent() {

    // 如果希望对父类的方法进行改进
    def run1(): Unit = {
      println("开自动驾驶的车 run...")
    }

    override def run(): Unit = {
    
      super.run() //在子类中,调用父类的方法
      
      println("开自动驾驶的车 run...")
    }
  }

  def main(args: Array[String]): Unit = {
    val s1 = new Son()
    s1.run()  //开自动驾驶的车 run...
  }
}

继承与多态

同一操作作用于不同的对象, 可以有不同的解释,产生不同的执行结果

案例

object class11 {
  class Fruit() {
    def eat(): Unit = {
      println("eat...")
    }
  }
  class Apple extends Fruit{
    override def eat(): Unit = {
      println("吃掉果皮,中间的不能吃")
    }
  }
  class Watermelon extends Fruit{
    override def eat(): Unit = {
      println("削皮,中间的最好吃")
    }
  }

  def main(args: Array[String]): Unit = {
    // 参数类型:父亲
    def test(fruit: Fruit): Unit = {
      fruit.eat()
    }

    val a1 = new Apple()
    test(a1)  //传入子类

    val w1 = new Watermelon()
    test(w1)
  }
}

处理构造器的调用顺序

1.调用顺序:父类的主构造器->子类主构造器->子类的辅助构造器

object class12 {
  class Father() {
    println("Father 的构造器...")
  }

  class Son extends Father(){
    println("Son 的构造器...")
  }
  def main(args: Array[String]): Unit = {
    // 创建一个子类对象时,先调用父类的构造器 -> 子类的构造器
    new Son()
  }
}

运行结果:

屏幕截图 2025-11-10 100430.png

2.当父类,子类都存在带参数的构造器的时候,如何进行参数传递?

object class13 {
  // 父类
  class Animal(var name:String,var age:Int) {
    def say(): Unit = {
      println(s"Animal ${name},${age}")
    }
  }

  // 子类
  class Dog(name:String,age:Int,var color:String) extends Animal(name, age){
    override def say(): Unit ={
      super.say()
      println(s"狗狗... ,我的颜色是${color}")
    }
  }

  def main(args: Array[String]): Unit = {
    val d1 = new Dog("旺财",1,"黑色")
    d1.say()
  }
}

Animal(name,age) 中, name, age的前面都没有添加修饰符。在子类构造函数调用的时候,就会执行这个函数,并进行参数传递。

屏幕截图 2025-11-10 101841.png

练习题

设计一个Point类,其x和y可以通过构造器提供。

它有几个方法:

1.方法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)

object class01 {
  class Point(var x:Double,var y:Double) {
    def whereAmI():String={
      if(x>0 && y>0){
        "第一象限"
      } else if(x>0 && y<0){
        "第四象限"
      } else if(x<0 && y<0){
        "第三象限"
      } else if(x<0 && y>0){
        "第二象限"
      } else if(x==0 && y!=0){
        "y轴上"
      } else if(y==0 && x!=0){
        "x轴上"
      } else if(x==0 && x==0){
        "原点"
      } else {
        "未知"
      }
    }
    
    def getDist():Double={
      Math.sqrt(this.x * this.x + this.y * this.y)
    }
    def fromPoint(other:Point):Double={
    Math.sqrt((this.x-other.x) * (this.x-other.x) + (this.y-other.y))
    }

    override def equals(obj:Any):Boolean={
      val other = obj.asInstanceOf[Point]
      this.x == other.x && this.y == other.y
    }

    override def toString:String = {
      s"Point(${x},${y})"
    }
  }
  
  def main(args: Array[String]): Unit = {
    val p1 = new Point(1,1)
    val p2 = new Point(1,1)
    println(p1 == p2)
    println(p1.whereAmI())
    println(p1.getDist())
    println(p1.fromPoint(p2))

  }
}