scala中的内部类

59 阅读2分钟

一、内部类的定义

在 Scala 中,内部类是定义在另一个类(外部类)内部的类。它的语法形式如下:

class 外部类 { class 内部类 { // 内部类的成员定义 } }

内部类与外部类有着紧密的关联,它可以直接访问外部类的所有成员(包括私有成员),这是内部类实现高内聚封装的关键特性。

二、内部类的基本使用

我们通过一个简单的示例来演示内部类的基本使用:

package A2

object class15 {
  // 外部类:学校
  class School(val name: String) {
    // 内部类:学生
    class Student(val id: Int, var name: String) {
      def study(): Unit = {
        println(s"${this.name}(学号:$id)在${School.this.name}学校学习")
      }
    }

    // 创建学生对象的方法
    def createStudent(id: Int, name: String): Student = {
      new Student(id, name)
    }
  }

  // 测试代码
  object InnerClassDemo {
    def main(args: Array[String]): Unit = {
      val school = new School("北京大学")
      val student1 = school.createStudent(1, "张三")
      student1.study()

      val student2 = school.createStudent(2, "李四")
      student2.study()
    }
  }
}

在上述代码中,Student类是School类的内部类。需要注意的是,Scala 的内部类是 “路径依赖” 的,即不同外部类实例的内部类是不同的类型。例如,若有val school2 = new School("清华大学"),则school.createStudent(...)的类型与school2.createStudent(...)的类型并不兼容。

三、内部类的使用案例:小汽车与发动机的封装

我们按照案例要求,实现一个包含内部类的小汽车系统:

package A2

object class15 {
  // 外部类:小汽车
  class Car {
    // 私有变量:速度
    private var speed: Double = 0.0

    // 内部类:发动机
    class Engine {
      // 加速方法:修改外部类的私有变量speed
      def accelerate(inc: Double): Unit = {
        speed += inc
        println(s"加速后,车速为:$speed km/h")
      }

      // 减速方法
      def decelerate(dec: Double): Unit = {
        speed = if (speed - dec < 0) 0 else speed - dec
        println(s"减速后,车速为:$speed km/h")
      }
    }

    // 获取发动机对象的方法
    def getEngine: Engine = {
      new Engine
    }
  }

  // 测试代码
  object CarDemo {
    def main(args: Array[String]): Unit = {
      val car = new Car
      val engine = car.getEngine

      engine.accelerate(50)
      engine.accelerate(30)
      engine.decelerate(20)
    }
  }
}

在这个案例中,Engine作为Car的内部类,能够直接访问Car的私有变量speed,从而实现对车速的修改。这种设计将 “发动机” 与 “小汽车” 的逻辑紧密封装在一起,符合面向对象的高内聚原则。

四、内部对象

在 Scala 中,除了内部类,还可以定义内部对象(也称为嵌套对象)。内部对象是定义在类或对象内部的单例对象,它常用于实现类的伴生对象、工具类封装等场景。

示例如下:

package A2

object class15 {
  class MathUtils {
    // 内部对象:包含数学工具方法
    object Calculator {
      def add(a: Int, b: Int): Int = a + b
      def multiply(a: Int, b: Int): Int = a * b
    }
  }

  // 测试内部对象
  object InnerObjectDemo {
    def main(args: Array[String]): Unit = {
      val math = new MathUtils
      println(s"2 + 3 = ${math.Calculator.add(2, 3)}")
      println(s"2 × 3 = ${math.Calculator.multiply(2, 3)}")
    }
  }
}

内部对象的一个典型应用是伴生对象的嵌套,例如在一个内部类中定义其伴生对象,用于创建该内部类的实例:

package A2

object class15 {
  class Outer {
    class Inner private(val name: String)
    // 内部伴生对象
    object Inner {
      def apply(name: String): Inner = new Inner(name)
    }
  }

  object OuterDemo {
    def main(args: Array[String]): Unit = {
      val outer = new Outer
      val inner = outer.Inner("内部类实例")
      println(inner.name)
    }
  }
}

匿名类是指没有显式命名的类,它通常用于快速实现一个特质(trait)或抽象类的实例,而无需定义一个新的具名类。

在 Scala 中,匿名类的语法形式为:new 特质/抽象类 { 实现代码 }

5.1 匿名类实现特质

package A2

object class15 {
  // 定义一个特质
  trait Greeting {
    def sayHello(name: String): Unit
  }

  // 使用匿名类实现特质
  object AnonymousClassDemo {
    def main(args: Array[String]): Unit = {
      val chineseGreeting = new Greeting {
        override def sayHello(name: String): Unit = {
          println(s"你好,$name!")
        }
      }

      val englishGreeting = new Greeting {
        override def sayHello(name: String): Unit = {
          println(s"Hello, $name!")
        }
      }

      chineseGreeting.sayHello("张三")
      englishGreeting.sayHello("John")
    }
  }
}

5.2 匿名类实现抽象类

package A2

object class15 {
  // 抽象类
  abstract class Animal {
    def sound(): Unit
  }

  // 匿名类实现抽象类
  object AnimalDemo {
    def main(args: Array[String]): Unit = {
      val dog = new Animal {
        override def sound(): Unit = {
          println("汪汪汪!")
        }
      }

      val cat = new Animal {
        override def sound(): Unit = {
          println("喵喵喵!")
        }
      }

      dog.sound()
      cat.sound()
    }
  }
}

匿名类的优势在于快速原型开发代码简洁性,尤其在只需要一个类的单次实例时,避免了定义具名类的繁琐。

总结

本文围绕 Scala 的内部类、内部对象和匿名类展开,从定义、基本使用到实战案例,全面解析了这些特性的用法与价值:

  • 内部类通过嵌套定义实现类之间的强逻辑关联,支持访问外部类私有成员,是封装复杂逻辑的有力工具。
  • 内部对象常用于工具方法封装、伴生对象嵌套等场景,提升代码的内聚性。
  • 匿名类则让我们可以快速实现特质或抽象类的实例,简化代码结构,尤其适用于临时逻辑的快速实现。