Scala中的内部类

72 阅读8分钟

1. 内部类的定义;

2. 内部类的基本使用;

3. 内部类的综合案例;

4. 内部对象;

5. 匿名类。

(一)内部类的定义

定义在类或者对象内部的类称为内部类。

在类的内部有:属性,方法,类。

image.png

1. 基本语法

内部类的基本定义格式

class OuterClass {     // 外部类
    // 外部类的成员
    
    class InnerClass {  // 内部类
        // 内部类的成员
    }
}

具体示例

object InnerClassDefinition {
    
    // 外部类
    class Car(val brand: String, var speed: Int = 0) {
        // 外部类属性
        private val maxSpeed: Int = 200
        
        // 外部类方法
        def accelerate(amount: Int): Unit = {
            speed = Math.min(speed + amount, maxSpeed)
            println(s"$brand 加速到 $speed km/h")
        }
        
        // 内部类定义
        class Engine(val engineType: String, val horsepower: Int) {
            // 内部类属性
            private var isRunning: Boolean = false
            
            // 内部类方法
            def start(): Unit = {
                if (!isRunning) {
                    isRunning = true
                    println(s"$brand$engineType 引擎启动,马力: $horsepower")
                    // 内部类可以访问外部类的成员
                    accelerate(20)
                }
            }
            
            def stop(): Unit = {
                if (isRunning) {
                    isRunning = false
                    println(s"$brand 的引擎停止")
                    speed = 0
                }
            }
            
            def getStatus(): String = {
                s"引擎类型: $engineType, 运行状态: $isRunning, 当前车速: $speed"
            }
            
            // 内部类可以访问外部类的私有成员
            def canReachMaxSpeed(): Boolean = {
                horsepower >= 150 && maxSpeed >= 180
            }
        }
    }
}

2. 内部类的实例化

创建内部类对象

object InnerClassInstantiation {
    
    class University(val name: String) {
        class Department(val deptName: String) {
            def info(): String = s"$name - $deptName"
        }
    }
    
    def main(args: Array[String]): Unit = {
        // 创建外部类实例
        val tsinghua = new University("清华大学")
        val beida = new University("北京大学")
        
        // 创建内部类实例(必须通过外部类实例)
        val tsinghuaCS = new tsinghua.Department("计算机系")
        val tsinghuaMath = new tsinghua.Department("数学系")
        val beidaCS = new beida.Department("计算机系")
        
        println(tsinghuaCS.info())  // 清华大学 - 计算机系
        println(tsinghuaMath.info()) // 清华大学 - 数学系  
        println(beidaCS.info())     // 北京大学 - 计算机系
        
        // 类型路径依赖
        println(s"类型比较: ${tsinghuaCS.getClass == beidaCS.getClass}") // false
    }
}

3. 内部类访问外部类成员

完整的访问权限示例

object InnerClassAccess {
    
    class Bank(val bankName: String) {
        private var totalBalance: Double = 0.0
        private val interestRate: Double = 0.03
        
        class Account(val accountHolder: String, var balance: Double) {
            // 内部类可以访问外部类的私有字段
            def deposit(amount: Double): Unit = {
                balance += amount
                totalBalance += amount  // 修改外部类的私有字段
                println(s"$accountHolder 存款 $amount, 余额: $balance")
            }
            
            def withdraw(amount: Double): Boolean = {
                if (balance >= amount) {
                    balance -= amount
                    totalBalance -= amount
                    println(s"$accountHolder 取款 $amount, 余额: $balance")
                    true
                } else {
                    println(s"$accountHolder 取款失败,余额不足")
                    false
                }
            }
            
            def applyInterest(): Unit = {
                val interest = balance * interestRate  // 访问外部类私有常量
                balance += interest
                totalBalance += interest
                println(s"$accountHolder 获得利息 $interest, 新余额: $balance")
            }
            
            def getBankInfo(): String = {
                s"银行: $bankName, 总余额: $totalBalance"  // 访问外部类字段
            }
        }
        
        def getTotalBalance(): Double = totalBalance
        def getAccountCount(): Int = {
            // 这里无法直接获取内部类实例数量,需要其他机制
            0
        }
    }
    
    def main(args: Array[String]): Unit = {
        val bank = new Bank("中国银行")
        
        val account1 = new bank.Account("张三", 1000)
        val account2 = new bank.Account("李四", 2000)
        
        account1.deposit(500)
        account2.withdraw(300)
        account1.applyInterest()
        
        println(account1.getBankInfo())
        println(s"银行总余额: ${bank.getTotalBalance()}")
    }
}

4. 多层内部类

嵌套的内部类结构

object MultiLevelInnerClass {
    
    class Company(val companyName: String) {
        private var totalEmployees = 0
        
        class Department(val deptName: String) {
            private var deptEmployees = 0
            
            class Team(val teamName: String) {
                private var teamMembers = 0
                
                def hire(employee: String): Unit = {
                    teamMembers += 1
                    deptEmployees += 1
                    totalEmployees += 1
                    println(s"$companyName - $deptName - $teamName 招聘: $employee")
                    println(s"团队人数: $teamMembers, 部门人数: $deptEmployees, 公司总人数: $totalEmployees")
                }
                
                class Employee(val name: String, val position: String) {
                    def work(): Unit = {
                        println(s"$name ($position) 在 $companyName - $deptName - $teamName 工作")
                    }
                    
                    def getOrgPath(): String = {
                        s"$companyName -> $deptName -> $teamName -> $name"
                    }
                }
            }
            
            def createTeam(teamName: String): Team = {
                new Team(teamName)
            }
        }
        
        def createDepartment(deptName: String): Department = {
            new Department(deptName)
        }
    }
    
    def main(args: Array[String]): Unit = {
        val company = new Company("阿里巴巴")
        
        val techDept = company.createDepartment("技术部")
        val marketDept = company.createDepartment("市场部")
        
        val backendTeam = techDept.createTeam("后端团队")
        val frontendTeam = techDept.createTeam("前端团队")
        val salesTeam = marketDept.createTeam("销售团队")
        
        backendTeam.hire("张三")
        frontendTeam.hire("李四")
        salesTeam.hire("王五")
        
        // 创建最内层的内部类
        val employee1 = new backendTeam.Employee("赵六", "高级工程师")
        employee1.work()
        println(employee1.getOrgPath())
    }
}

5. 内部类的类型路径

路径依赖类型

object PathDependentTypes {
    
    class Container(val id: String) {
        class Item(val name: String) {
            def describe(): String = s"容器 $id 中的物品 $name"
        }
    }
    
    def processItem(item: Container#Item): Unit = {
        // Container#Item 是类型投影,不依赖特定实例
        println(s"处理: ${item.name}")
    }
    
    def main(args: Array[String]): Unit = {
        val container1 = new Container("A")
        val container2 = new Container("B")
        
        val item1 = new container1.Item("书籍")
        val item2 = new container2.Item("电脑")
        
        // 这些是不同类型
        // val item3: container1.Item = new container2.Item("手机") // 编译错误
        
        // 使用类型投影可以接受任何容器的Item
        processItem(item1)
        processItem(item2)
        
        println(item1.describe()) // 容器 A 中的物品 书籍
        println(item2.describe()) // 容器 B 中的物品 电脑
    }
}

关键特点总结:

  1. 定义位置:在外部类的内部定义
  2. 实例绑定:每个内部类实例与特定的外部类实例关联
  3. 访问权限:可以访问外部类的所有成员(包括私有成员)
  4. 类型路径outerInstance.InnerClass 是路径依赖类型
  5. 创建方式:必须通过外部类实例创建 new outer.Inner()
  6. 内存模型:内部类隐式持有对外部类实例的引用

(二)内部类的基本使用

定义格式: class 类 {  class 内部类 }

使用格式: new 类的实例.内部类()

/*
  * 内部类
  ***/
object Main {
    // 外部类
    class Car() {
        var wheel: Int = 4
        def run(): Unit = {
            println("run...")
        }
        // 内部类
        class Engine() {
            val power: Int = 120
            def start(): Unit = {
                println("引擎启动")
            }
        }
    }

    def main(args: Array[String]): Unit = {
        val car = new Car()
        // Scala 中创建内部类的方式
        val engine = new car.Engine()
        println(engine.power)
        engine.start()
        car.run()
    }
}

关键点总结:

  1. 创建语法new outerInstance.InnerClass()
  2. 实例绑定:内部类实例与特定的外部类实例绑定
  3. 访问权限:内部类可以访问外部类的所有成员(包括私有成员)
  4. 类型路径car1.Engine 和 car2.Engine 是不同的类型
  5. 内存模型:内部类持有对外部类实例的引用

内部类的好处

(1)逻辑组织:引擎与 汽车紧密相关,它们都属于汽车的上下文。将它们作为内部类可以使代码更为整洁和逻辑清晰。

(2)简化访问:内部类能够方便地访问外部类的私有成员,这样引擎类可以操作汽车的速度而不需要通过外部接口。

(3)减少命名冲突:由于内部类的作用范围限制在外部类内,避免了名称冲突(在大型项目中,可能会有多个引擎类)。

(三)内部类的使用案例

1. 游戏角色系统

object GameCharacterExample {
    
    class GameCharacter(val name: String, var health: Int = 100) {
        private var position: (Int, Int) = (0, 0)
        private var experience: Int = 0
        
        // 装备内部类
        class Equipment(val slot: String) {
            private var item: Option[String] = None
            
            def equip(itemName: String): Unit = {
                item = Some(itemName)
                println(s"$name 装备了 $slot: $itemName")
            }
            
            def unequip(): Unit = {
                item.foreach { oldItem =>
                    println(s"$name 卸下了 $slot: $oldItem")
                }
                item = None
            }
            
            def getItem: Option[String] = item
            
            def applyBonus(): Int = item match {
                case Some("王者之剑") => 20
                case Some("守护之盾") => 15
                case Some("疾风之靴") => 10
                case _ => 0
            }
        }
        
        // 技能内部类
        class Skill(val skillName: String, val cost: Int) {
            def use(target: GameCharacter): Unit = {
                if (health > cost) {
                    health -= cost
                    experience += 5
                    val damage = 10 + (experience / 10)
                    target.health -= damage
                    println(s"$name${target.name} 使用 $skillName, 造成 $damage 伤害")
                } else {
                    println(s"生命值不足,无法使用 $skillName")
                }
            }
            
            def upgrade(): Unit = {
                println(s"$skillName 技能升级!")
            }
        }
        
        // 背包内部类
        class Inventory {
            private var items: List[String] = List()
            private val capacity = 10
            
            def addItem(item: String): Boolean = {
                if (items.length < capacity) {
                    items = item :: items
                    println(s"$name 获得了 $item")
                    true
                } else {
                    println("背包已满")
                    false
                }
            }
            
            def useItem(item: String): Boolean = {
                if (items.contains(item)) {
                    items = items.filter(_ != item)
                    item match {
                        case "治疗药水" => health = Math.min(health + 30, 100)
                        case "魔力药水" => experience += 10
                    }
                    println(s"$name 使用了 $item")
                    true
                } else {
                    println(s"没有 $item")
                    false
                }
            }
            
            def showItems(): Unit = {
                println(s"$name 的背包: ${items.mkString(", ")}")
            }
        }
        
        def moveTo(x: Int, y: Int): Unit = {
            position = (x, y)
            println(s"$name 移动到位置 ($x, $y)")
        }
        
        def showStatus(): Unit = {
            println(s"角色: $name, 生命: $health, 经验: $experience, 位置: $position")
        }
    }

    def main(args: Array[String]): Unit = {
        val warrior = new GameCharacter("战士")
        val mage = new GameCharacter("法师", 80)
        
        // 创建装备
        val weapon = new warrior.Equipment("武器")
        val armor = new warrior.Equipment("护甲")
        val boots = new warrior.Equipment("靴子")
        
        // 创建技能
        val slash = new warrior.Skill("斩击", 15)
        val fireball = new mage.Skill("火球术", 20)
        
        // 创建背包
        val inventory = new warrior.Inventory()
        
        warrior.showStatus()
        
        // 装备物品
        weapon.equip("王者之剑")
        armor.equip("守护之盾")
        boots.equip("疾风之靴")
        
        // 使用技能
        slash.use(mage)
        fireball.use(warrior)
        
        // 背包操作
        inventory.addItem("治疗药水")
        inventory.addItem("魔力药水")
        inventory.showItems()
        inventory.useItem("治疗药水")
        
        warrior.showStatus()
        mage.showStatus()
    }
}

2. 电商订单系统

object ECommerceExample {
    
    class Order(val orderId: String, val customer: String) {
        private var orderStatus: String = "待支付"
        private var totalAmount: Double = 0.0
        private var paymentMethod: Option[String] = None
        
        // 订单项内部类
        class OrderItem(val productId: String, val productName: String, var quantity: Int, val unitPrice: Double) {
            def calculateSubtotal(): Double = quantity * unitPrice
            
            def updateQuantity(newQuantity: Int): Unit = {
                totalAmount -= calculateSubtotal()  // 减去旧的
                quantity = newQuantity
                totalAmount += calculateSubtotal()  // 加上新的
                println(s"更新数量: $productName × $newQuantity")
            }
            
            def getItemInfo(): String = {
                s"$productName (ID: $productId) - $quantity × ¥$unitPrice = ¥${calculateSubtotal()}"
            }
        }
        
        // 支付内部类
        class Payment {
            def processPayment(method: String, amount: Double): Boolean = {
                if (orderStatus == "待支付" && amount >= totalAmount) {
                    paymentMethod = Some(method)
                    orderStatus = "已支付"
                    println(s"订单 $orderId 支付成功,方式: $method,金额: ¥$amount")
                    true
                } else {
                    println("支付失败")
                    false
                }
            }
            
            def refund(reason: String): Boolean = {
                if (orderStatus == "已支付") {
                    orderStatus = "已退款"
                    println(s"订单 $orderId 退款成功,原因: $reason")
                    true
                } else {
                    println("无法退款")
                    false
                }
            }
        }
        
        // 物流内部类
        class Shipping {
            private var trackingNumber: Option[String] = None
            private var shippingAddress: String = ""
            
            def setAddress(address: String): Unit = {
                shippingAddress = address
                println(s"设置收货地址: $address")
            }
            
            def ship(tracking: String): Unit = {
                if (orderStatus == "已支付") {
                    trackingNumber = Some(tracking)
                    orderStatus = "已发货"
                    println(s"订单 $orderId 已发货,物流单号: $tracking")
                } else {
                    println("订单未支付,无法发货")
                }
            }
            
            def track(): Unit = {
                trackingNumber match {
                    case Some(tracking) => println(s"物流跟踪: $tracking -> $shippingAddress")
                    case None => println("尚未发货")
                }
            }
        }
        
        def addItem(item: OrderItem): Unit = {
            totalAmount += item.calculateSubtotal()
        }
        
        def getOrderSummary(): String = {
            s"订单 $orderId - 客户: $customer, 状态: $orderStatus, 总金额: ¥$totalAmount, 支付方式: ${paymentMethod.getOrElse("未支付")}"
        }
    }

    def main(args: Array[String]): Unit = {
        val order = new Order("ORD001", "张三")
        
        // 创建订单项
        val item1 = new order.OrderItem("P001", "iPhone 15", 1, 5999.0)
        val item2 = new order.OrderItem("P002", "AirPods", 2, 1299.0)
        
        // 添加到订单
        order.addItem(item1)
        order.addItem(item2)
        
        println(order.getOrderSummary())
        println(item1.getItemInfo())
        println(item2.getItemInfo())
        
        // 更新数量
        item2.updateQuantity(1)
        println(order.getOrderSummary())
        
        // 支付
        val payment = new order.Payment()
        payment.processPayment("支付宝", 7297.0)
        
        // 物流
        val shipping = new order.Shipping()
        shipping.setAddress("北京市海淀区")
        shipping.ship("SF123456789")
        shipping.track()
        
        println(order.getOrderSummary())
    }
}

3. 学校管理系统

object SchoolManagementExample {
    
    class School(val schoolName: String) {
        private var studentCount = 0
        
        // 班级内部类
        class Classroom(val grade: Int, val className: String) {
            private var students: List[String] = List()
            private val teacher: String = s"${grade}年级班主任"
            
            // 学生内部类(嵌套内部类)
            class Student(val studentName: String, val studentId: String) {
                private var scores: Map[String, Int] = Map()
                
                def enroll(): Unit = {
                    students = studentName :: students
                    studentCount += 1
                    println(s"学生 $studentName 加入 $grade 年级 $className")
                }
                
                def addScore(subject: String, score: Int): Unit = {
                    scores += (subject -> score)
                    println(s"$studentName$subject 成绩: $score")
                }
                
                def getAverageScore(): Double = {
                    if (scores.isEmpty) 0.0
                    else scores.values.sum.toDouble / scores.size
                }
                
                def getStudentInfo(): String = {
                    s"学生: $studentName (ID: $studentId), 班级: $grade-$className, 平均分: ${getAverageScore()}"
                }
                
                def getClassInfo(): String = {
                    s"班级: $grade-$className, 班主任: $teacher, 同学: ${students.mkString(", ")}"
                }
            }
            
            def getStudentList(): List[String] = students
            
            def getClassSummary(): String = {
                s"$grade 年级 $className - 学生人数: ${students.length}, 班主任: $teacher"
            }
        }
        
        // 课程内部类
        class Course(val courseName: String, val credit: Int) {
            private var enrolledStudents: Set[String] = Set()
            
            def enrollStudent(studentName: String): Unit = {
                enrolledStudents += studentName
                println(s"$studentName 选修了 $courseName")
            }
            
            def getEnrolledStudents(): Set[String] = enrolledStudents
            
            def getCourseInfo(): String = {
                s"课程: $courseName, 学分: $credit, 选课人数: ${enrolledStudents.size}"
            }
        }
        
        def getTotalStudents(): Int = studentCount
    }

    def main(args: Array[String]): Unit = {
        val school = new School("第一中学")
        
        // 创建班级
        val class1 = new school.Classroom(1, "一班")
        val class2 = new school.Classroom(1, "二班")
        
        // 创建学生
        val student1 = new class1.Student("张三", "S001")
        val student2 = new class1.Student("李四", "S002")
        val student3 = new class2.Student("王五", "S003")
        
        // 学生入学
        student1.enroll()
        student2.enroll()
        student3.enroll()
        
        // 添加成绩
        student1.addScore("数学", 95)
        student1.addScore("语文", 88)
        student2.addScore("数学", 92)
        student2.addScore("语文", 85)
        
        // 创建课程
        val mathCourse = new school.Course("高等数学", 4)
        val physicsCourse = new school.Course("大学物理", 3)
        
        // 选课
        mathCourse.enrollStudent("张三")
        mathCourse.enrollStudent("李四")
        physicsCourse.enrollStudent("张三")
        
        // 输出信息
        println(student1.getStudentInfo())
        println(student2.getStudentInfo())
        println(student1.getClassInfo())
        println(class1.getClassSummary())
        println(class2.getClassSummary())
        println(mathCourse.getCourseInfo())
        println(physicsCourse.getCourseInfo())
        println(s"学校总人数: ${school.getTotalStudents()}")
    }
}

4. 车辆管理系统

object VehicleManagementExample {
    
    class VehicleFleet(val company: String) {
        private var totalMileage = 0.0
        private var maintenanceCost = 0.0
        
        // 车辆内部类
        class Vehicle(val licensePlate: String, val model: String) {
            private var currentMileage = 0.0
            private var fuelLevel = 100.0
            private var needsMaintenance = false
            
            // 行程内部类
            class Trip(val driver: String, val destination: String) {
                private var distance = 0.0
                private var completed = false
                
                def startTrip(initialDistance: Double): Unit = {
                    distance = initialDistance
                    println(s"$driver 驾驶 $licensePlate 前往 $destination,开始行程")
                }
                
                def updateDistance(additionalDistance: Double): Unit = {
                    distance += additionalDistance
                    currentMileage += additionalDistance
                    totalMileage += additionalDistance
                    fuelLevel -= additionalDistance * 0.1  // 每公里耗油0.1%
                    
                    if (fuelLevel < 10) {
                        println("警告:燃油不足!")
                    }
                    
                    if (currentMileage > 10000 && !needsMaintenance) {
                        needsMaintenance = true
                        println("车辆需要保养!")
                    }
                }
                
                def completeTrip(): Unit = {
                    completed = true
                    println(s"行程完成: $destination, 总距离: $distance 公里")
                }
                
                def getTripSummary(): String = {
                    s"司机: $driver, 目的地: $destination, 距离: $distance 公里, 完成: $completed"
                }
            }
            
            // 维护内部类
            class Maintenance {
                def performMaintenance(cost: Double): Unit = {
                    maintenanceCost += cost
                    currentMileage = 0  // 重置保养里程
                    needsMaintenance = false
                    fuelLevel = 100.0
                    println(s"车辆 $licensePlate 保养完成,花费: ¥$cost")
                }
                
                def refuel(amount: Double): Unit = {
                    fuelLevel = Math.min(fuelLevel + amount, 100.0)
                    println(s"车辆 $licensePlate 加油 $amount%,当前油量: $fuelLevel%")
                }
            }
            
            def getVehicleStatus(): String = {
                s"车辆: $licensePlate ($model), 里程: $currentMileage km, 油量: $fuelLevel%, 需要保养: $needsMaintenance"
            }
        }
        
        def getFleetSummary(): String = {
            s"车队: $company, 总里程: $totalMileage km, 总维护成本: ¥$maintenanceCost"
        }
    }

    def main(args: Array[String]): Unit = {
        val fleet = new VehicleFleet("顺丰快递")
        
        val truck1 = new fleet.Vehicle("京A12345", "重型卡车")
        val van1 = new fleet.Vehicle("京B67890", "厢式货车")
        
        // 创建行程
        val trip1 = new truck1.Trip("张三", "上海")
        val trip2 = new van1.Trip("李四", "天津")
        
        // 开始行程
        trip1.startTrip(0)
        trip1.updateDistance(1200)
        trip1.completeTrip()
        
        trip2.startTrip(0)
        trip2.updateDistance(800)
        trip2.completeTrip()
        
        // 车辆维护
        val maintenance1 = new truck1.Maintenance()
        maintenance1.refuel(50)
        maintenance1.performMaintenance(500.0)
        
        // 输出状态
        println(truck1.getVehicleStatus())
        println(van1.getVehicleStatus())
        println(trip1.getTripSummary())
        println(trip2.getTripSummary())
        println(fleet.getFleetSummary())
    }
}

这些案例展示了内部类在实际项目中的应用,体现了内部类与外部类实例的紧密关联性和数据封装的优势。

(四)内部对象

内部对象,就是定义在class内部的object。

定义格式: class 类名 {  object 对象名{ 属性;方法() }}

使用格式:类名.对象名.属性名; 类名.对象名.方法名()

/*
* 内部类
* 1. 格式:在一个类的里面,再写一个类
* 2. 作用:组织逻辑更加严谨,避免命名的冲突
*/
object base66 {
  // 外部类
  class Car() {
    var wheel: Int = 4
    // 私有成员
    private var speed: Int = 0

    def run(): Unit = {
      println(s"速度为: ${speed}, run...")
    }

    // 内部类
    class Engine() {
      def acc(increment: Int): Unit = {
        speed += increment  // 内部类可以直接访问外部类的私有成员!
      }

      def getSpeed(): Int = {
        speed  // 访问私有成员
      }
    }

    class AutoPark() {
      def park(): Unit = {
        speed = 0  // 另一个内部类也可以访问同一个外部类的私有成员
        println("自动泊车完成,速度归零")
      }
    }
  }

  def main(args: Array[String]): Unit = {
    val car1 = new Car()
    // car1.speed  // 错误:私有成员不能在类外部访问
    car1.run()  // 速度为: 0, run...

    val engine = new car1.Engine()
    engine.acc(10)  // 内部类修改外部类的私有成员
    car1.run()      // 速度为: 10, run...

    val park = new car1.AutoPark()
    park.park()     // 自动泊车完成,速度归零
    car1.run()      // 速度为: 0, run...

    println(s"通过引擎获取速度: ${engine.getSpeed()}")
  }
}

关键特性验证:

✅ 内部类可以直接访问外部类的私有成员

  • speed(私有变量)
  • fuel(私有变量)
  • maxSpeed(私有常量)

✅ 多个内部类可以访问同一个外部类实例的成员

  • EngineFuelSystemAirCondition 都操作同一个 Car 实例

✅ 内部类之间可以通过外部类实例间接交互

  • 空调影响燃油消耗
  • 燃油系统可以紧急制动

这充分证明了内部类与外部类实例的紧密关联性!

(五)匿名类

匿名类指没有名字的类。匿名类只能使用一次。