Scala 类和对象
类和对象是面向对象编程的核心概念。本章将详细介绍 Scala 中类的定义、对象的创建、继承、多态等面向对象编程的基本概念。
类的定义
基本类定义
scala
// 基本类定义
class Person {
// 类体
}
// 创建对象
val person = new Person()
// 带参数的类
class Student(name: String, age: Int) {
// 主构造函数参数自动成为类的字段
def introduce(): String = s"Hi, I'm $name and I'm $age years old"
}
val student = new Student("Alice", 20)
println(student.introduce())构造函数参数
scala
// val 参数:不可变字段
class Person(val name: String, val age: Int) {
// name 和 age 自动成为公共的不可变字段
}
val person = new Person("Bob", 25)
println(person.name) // 可以访问
println(person.age) // 可以访问
// person.age = 26 // 编译错误:不能修改
// var 参数:可变字段
class Counter(var count: Int) {
def increment(): Unit = count += 1
def decrement(): Unit = count -= 1
}
val counter = new Counter(0)
counter.increment()
println(counter.count) // 1
counter.count = 10 // 可以直接修改私有参数
scala
// 私有参数:不生成字段
class BankAccount(private var balance: Double) {
def deposit(amount: Double): Unit = {
if (amount > 0) balance += amount
}
def withdraw(amount: Double): Boolean = {
if (amount > 0 && amount <= balance) {
balance -= amount
true
} else {
false
}
}
def getBalance: Double = balance // 只读访问
}
val account = new BankAccount(1000.0)
account.deposit(500.0)
println(account.getBalance) // 1500.0
// println(account.balance) // 编译错误:私有字段方法和字段
实例方法
scala
class Calculator {
def add(x: Int, y: Int): Int = x + y
def multiply(x: Int, y: Int): Int = x * y
// 方法可以访问类的字段
private var history: List[String] = List()
def addWithHistory(x: Int, y: Int): Int = {
val result = x + y
history = s"$x + $y = $result" :: history
result
}
def getHistory: List[String] = history.reverse
}
val calc = new Calculator()
calc.addWithHistory(3, 4)
calc.addWithHistory(5, 6)
println(calc.getHistory) // List("3 + 4 = 7", "5 + 6 = 11")字段初始化
scala
class Person(firstName: String, lastName: String) {
// 计算字段
val fullName: String = s"$firstName $lastName"
// 延迟初始化字段
lazy val initials: String = {
println("Computing initials...")
s"${firstName.head}.${lastName.head}."
}
// 可变字段
var nickname: String = firstName
// 私有字段
private var id: Int = Person.nextId()
def getId: Int = id
}
object Person {
private var currentId = 0
private def nextId(): Int = {
currentId += 1
currentId
}
}
val person = new Person("John", "Doe")
println(person.fullName) // "John Doe"
println(person.initials) // 此时才计算
println(person.getId) // 1辅助构造函数
scala
class Person(val name: String, val age: Int) {
// 辅助构造函数必须调用主构造函数或其他辅助构造函数
def this(name: String) = {
this(name, 0) // 调用主构造函数
}
def this() = {
this("Unknown") // 调用上面的辅助构造函数
}
override def toString: String = s"Person($name, $age)"
}
// 使用不同的构造函数
val person1 = new Person("Alice", 25)
val person2 = new Person("Bob")
val person3 = new Person()
println(person1) // Person(Alice, 25)
println(person2) // Person(Bob, 0)
println(person3) // Person(Unknown, 0)对象(Object)
单例对象
scala
// 单例对象
object MathUtils {
val PI: Double = 3.14159
def square(x: Double): Double = x * x
def circleArea(radius: Double): Double = PI * square(radius)
private var callCount = 0
def getCallCount: Int = {
callCount += 1
callCount
}
}
// 使用单例对象
println(MathUtils.PI)
println(MathUtils.circleArea(5.0))
println(MathUtils.getCallCount) // 1
println(MathUtils.getCallCount) // 2伴生对象
scala
// 类和其伴生对象可以互相访问私有成员
class BankAccount private (private var balance: Double) {
def deposit(amount: Double): Unit = {
balance += amount
}
def getBalance: Double = balance
// 访问伴生对象的私有成员
def getNextAccountNumber: String = BankAccount.nextAccountNumber()
}
object BankAccount {
private var accountCounter = 0
// 工厂方法
def apply(initialBalance: Double): BankAccount = {
new BankAccount(initialBalance)
}
def apply(): BankAccount = {
new BankAccount(0.0)
}
private def nextAccountNumber(): String = {
accountCounter += 1
f"ACC$accountCounter%06d"
}
// 访问类的私有成员
def transfer(from: BankAccount, to: BankAccount, amount: Double): Boolean = {
if (from.balance >= amount) {
from.balance -= amount
to.balance += amount
true
} else {
false
}
}
}
// 使用伴生对象
val account1 = BankAccount(1000.0) // 使用 apply 方法
val account2 = BankAccount() // 使用无参 apply 方法
account1.deposit(500.0)
BankAccount.transfer(account1, account2, 200.0)
println(account1.getBalance) // 1300.0
println(account2.getBalance) // 200.0案例类(Case Class)
基本案例类
scala
// 案例类自动生成很多有用的方法
case class Person(name: String, age: Int)
val person1 = Person("Alice", 25) // 不需要 new 关键字
val person2 = Person("Alice", 25)
// 自动生成的方法
println(person1) // Person(Alice,25) - toString
println(person1 == person2) // true - equals
println(person1.hashCode) // 自动生成的 hashCode
// 模式匹配支持
person1 match {
case Person(name, age) => println(s"Name: $name, Age: $age")
}
// copy 方法
val person3 = person1.copy(age = 26)
println(person3) // Person(Alice,26)
// 字段访问
println(person1.name) // Alice
println(person1.age) // 25案例类的高级特性
scala
case class Address(street: String, city: String, zipCode: String)
case class Person(
name: String,
age: Int,
email: Option[String] = None,
address: Option[Address] = None
) {
// 可以添加自定义方法
def isAdult: Boolean = age >= 18
def hasEmail: Boolean = email.isDefined
def fullAddress: String = address match {
case Some(addr) => s"${addr.street}, ${addr.city} ${addr.zipCode}"
case None => "No address"
}
}
val address = Address("123 Main St", "New York", "10001")
val person = Person(
name = "John Doe",
age = 30,
email = Some("john@example.com"),
address = Some(address)
)
println(person.isAdult) // true
println(person.hasEmail) // true
println(person.fullAddress) // 123 Main St, New York 10001
// 嵌套 copy
val movedPerson = person.copy(
address = person.address.map(_.copy(city = "Boston"))
)继承
基本继承
scala
// 基类
class Animal(val name: String) {
def speak(): String = "Some sound"
def move(): String = "Moving"
// 可以被重写的方法
def describe(): String = s"This is $name"
}
// 派生类
class Dog(name: String, val breed: String) extends Animal(name) {
// 重写方法
override def speak(): String = "Woof!"
override def describe(): String = s"This is $name, a $breed dog"
// 新方法
def wagTail(): String = s"$name is wagging tail"
}
class Cat(name: String) extends Animal(name) {
override def speak(): String = "Meow!"
def purr(): String = s"$name is purring"
}
// 使用继承
val dog = new Dog("Buddy", "Golden Retriever")
val cat = new Cat("Whiskers")
println(dog.speak()) // Woof!
println(dog.describe()) // This is Buddy, a Golden Retriever dog
println(dog.wagTail()) // Buddy is wagging tail
println(cat.speak()) // Meow!
println(cat.purr()) // Whiskers is purring抽象类
scala
// 抽象类
abstract class Shape {
// 抽象方法
def area(): Double
def perimeter(): Double
// 具体方法
def describe(): String = s"A shape with area ${area()} and perimeter ${perimeter()}"
}
class Rectangle(val width: Double, val height: Double) extends Shape {
def area(): Double = width * height
def perimeter(): Double = 2 * (width + height)
}
class Circle(val radius: Double) extends Shape {
def area(): Double = math.Pi * radius * radius
def perimeter(): Double = 2 * math.Pi * radius
}
val rectangle = new Rectangle(5.0, 3.0)
val circle = new Circle(2.0)
println(rectangle.describe())
println(circle.describe())
// 多态
val shapes: List[Shape] = List(rectangle, circle)
shapes.foreach(shape => println(s"Area: ${shape.area()}"))特征(Trait)
基本特征
scala
// 特征定义
trait Drawable {
def draw(): String
}
trait Movable {
def move(x: Int, y: Int): String
}
// 类可以混入多个特征
class Circle(val radius: Double) extends Drawable with Movable {
def draw(): String = s"Drawing a circle with radius $radius"
def move(x: Int, y: Int): String = s"Moving circle to ($x, $y)"
}
class Rectangle(val width: Double, val height: Double) extends Drawable with Movable {
def draw(): String = s"Drawing a rectangle ${width}x${height}"
def move(x: Int, y: Int): String = s"Moving rectangle to ($x, $y)"
}
val circle = new Circle(5.0)
val rectangle = new Rectangle(10.0, 8.0)
println(circle.draw())
println(rectangle.move(10, 20))带有默认实现的特征
scala
trait Logger {
// 抽象方法
def log(message: String): Unit
// 具体方法
def info(message: String): Unit = log(s"INFO: $message")
def error(message: String): Unit = log(s"ERROR: $message")
def debug(message: String): Unit = log(s"DEBUG: $message")
}
class ConsoleLogger extends Logger {
def log(message: String): Unit = println(message)
}
class FileLogger(filename: String) extends Logger {
def log(message: String): Unit = {
// 简化的文件写入
println(s"Writing to $filename: $message")
}
}
val consoleLogger = new ConsoleLogger()
val fileLogger = new FileLogger("app.log")
consoleLogger.info("Application started")
fileLogger.error("Database connection failed")访问修饰符
访问级别
scala
class AccessExample {
// 公共字段(默认)
val publicField = "public"
// 私有字段
private val privateField = "private"
// 受保护字段
protected val protectedField = "protected"
// 包私有
private[scala] val packagePrivateField = "package private"
def publicMethod(): String = "public method"
private def privateMethod(): String = "private method"
protected def protectedMethod(): String = "protected method"
// 只能在类内部访问私有成员
def accessPrivate(): String = privateMethod()
}
class SubClass extends AccessExample {
// 可以访问受保护成员
def accessProtected(): String = protectedMethod()
// 不能访问私有成员
// def accessPrivate(): String = privateMethod() // 编译错误
}实际应用示例
银行账户系统
scala
// 基础账户类
abstract class Account(val accountNumber: String, protected var balance: Double) {
def getBalance: Double = balance
def deposit(amount: Double): Boolean = {
if (amount > 0) {
balance += amount
true
} else {
false
}
}
// 抽象方法,由子类实现
def withdraw(amount: Double): Boolean
def transfer(to: Account, amount: Double): Boolean = {
if (withdraw(amount)) {
to.deposit(amount)
true
} else {
false
}
}
}
// 储蓄账户
class SavingsAccount(accountNumber: String, balance: Double, val interestRate: Double)
extends Account(accountNumber, balance) {
def withdraw(amount: Double): Boolean = {
if (amount > 0 && amount <= balance) {
balance -= amount
true
} else {
false
}
}
def addInterest(): Unit = {
balance += balance * interestRate
}
}
// 支票账户
class CheckingAccount(accountNumber: String, balance: Double, val overdraftLimit: Double)
extends Account(accountNumber, balance) {
def withdraw(amount: Double): Boolean = {
if (amount > 0 && amount <= balance + overdraftLimit) {
balance -= amount
true
} else {
false
}
}
def getAvailableBalance: Double = balance + overdraftLimit
}
// 使用示例
val savings = new SavingsAccount("SAV001", 1000.0, 0.02)
val checking = new CheckingAccount("CHK001", 500.0, 200.0)
savings.deposit(500.0)
savings.addInterest()
println(s"Savings balance: ${savings.getBalance}")
checking.withdraw(600.0) // 使用透支
println(s"Checking balance: ${checking.getBalance}")
println(s"Available balance: ${checking.getAvailableBalance}")
// 转账
savings.transfer(checking, 300.0)
println(s"After transfer - Savings: ${savings.getBalance}, Checking: ${checking.getBalance}")图形系统
scala
// 特征定义
trait Drawable {
def draw(): String
}
trait Scalable {
def scale(factor: Double): Unit
}
trait Colorable {
var color: String
def setColor(newColor: String): Unit = color = newColor
}
// 抽象基类
abstract class Shape extends Drawable {
def area(): Double
def perimeter(): Double
}
// 具体实现
class Circle(var radius: Double, var color: String = "black")
extends Shape with Scalable with Colorable {
def area(): Double = math.Pi * radius * radius
def perimeter(): Double = 2 * math.Pi * radius
def draw(): String = s"Drawing a $color circle with radius $radius"
def scale(factor: Double): Unit = radius *= factor
}
class Rectangle(var width: Double, var height: Double, var color: String = "black")
extends Shape with Scalable with Colorable {
def area(): Double = width * height
def perimeter(): Double = 2 * (width + height)
def draw(): String = s"Drawing a $color rectangle ${width}x${height}"
def scale(factor: Double): Unit = {
width *= factor
height *= factor
}
}
// 使用示例
val shapes: List[Shape with Scalable with Colorable] = List(
new Circle(5.0, "red"),
new Rectangle(10.0, 8.0, "blue")
)
shapes.foreach { shape =>
println(shape.draw())
println(s"Area: ${shape.area()}")
shape.scale(1.5)
shape.setColor("green")
println(s"After scaling and recoloring: ${shape.draw()}")
println(s"New area: ${shape.area()}")
println()
}练习
练习 1:学生管理系统
scala
object StudentManagementSystem {
case class Course(code: String, name: String, credits: Int)
case class Grade(course: Course, score: Double) {
def letterGrade: String = score match {
case s if s >= 90 => "A"
case s if s >= 80 => "B"
case s if s >= 70 => "C"
case s if s >= 60 => "D"
case _ => "F"
}
def isPass: Boolean = score >= 60
}
class Student(val id: String, val name: String) {
private var grades: List[Grade] = List()
def addGrade(grade: Grade): Unit = {
grades = grade :: grades
}
def getGrades: List[Grade] = grades.reverse
def gpa: Double = {
if (grades.isEmpty) 0.0
else {
val totalPoints = grades.map(g => g.score * g.course.credits).sum
val totalCredits = grades.map(_.course.credits).sum
totalPoints / totalCredits
}
}
def totalCredits: Int = grades.filter(_.isPass).map(_.course.credits).sum
override def toString: String = s"Student($id, $name, GPA: ${gpa})"
}
def main(args: Array[String]): Unit = {
val math = Course("MATH101", "Calculus I", 4)
val cs = Course("CS101", "Introduction to Programming", 3)
val english = Course("ENG101", "English Composition", 3)
val student = new Student("S001", "Alice Johnson")
student.addGrade(Grade(math, 85.0))
student.addGrade(Grade(cs, 92.0))
student.addGrade(Grade(english, 78.0))
println(student)
println(s"Total Credits: ${student.totalCredits}")
student.getGrades.foreach { grade =>
println(s"${grade.course.name}: ${grade.score} (${grade.letterGrade})")
}
}
}练习 2:电商系统
scala
object ECommerceSystem {
trait Discountable {
def applyDiscount(percentage: Double): Unit
}
abstract class Product(val id: String, val name: String, protected var price: Double) {
def getPrice: Double = price
override def toString: String = s"$name ($$${price})"
}
class Book(id: String, name: String, price: Double, val author: String, val isbn: String)
extends Product(id, name, price) with Discountable {
def applyDiscount(percentage: Double): Unit = {
price = price * (1 - percentage / 100)
}
override def toString: String = s"Book: $name by $author ($$${price})"
}
class Electronics(id: String, name: String, price: Double, val brand: String, val warranty: Int)
extends Product(id, name, price) with Discountable {
def applyDiscount(percentage: Double): Unit = {
price = price * (1 - percentage / 100)
}
override def toString: String = s"Electronics: $name by $brand ($$${price}, ${warranty}y warranty)"
}
case class CartItem(product: Product, quantity: Int) {
def totalPrice: Double = product.getPrice * quantity
}
class ShoppingCart {
private var items: List[CartItem] = List()
def addItem(product: Product, quantity: Int): Unit = {
items = CartItem(product, quantity) :: items
}
def removeItem(productId: String): Unit = {
items = items.filterNot(_.product.id == productId)
}
def getItems: List[CartItem] = items.reverse
def totalAmount: Double = items.map(_.totalPrice).sum
def applyBulkDiscount(percentage: Double): Unit = {
items.foreach { item =>
item.product match {
case discountable: Discountable => discountable.applyDiscount(percentage)
case _ => // 不支持折扣的产品
}
}
}
}
def main(args: Array[String]): Unit = {
val book = new Book("B001", "Scala Programming", 45.99, "Martin Odersky", "978-0981531687")
val laptop = new Electronics("E001", "MacBook Pro", 1299.99, "Apple", 1)
val cart = new ShoppingCart()
cart.addItem(book, 2)
cart.addItem(laptop, 1)
println("Shopping Cart:")
cart.getItems.foreach(item =>
println(s"${item.product} x ${item.quantity} = $$${item.totalPrice}")
)
println(s"Total: $$${cart.totalAmount}")
println("\nApplying 10% bulk discount...")
cart.applyBulkDiscount(10.0)
println("Updated Cart:")
cart.getItems.foreach(item =>
println(s"${item.product} x ${item.quantity} = $$${item.totalPrice}")
)
println(s"New Total: $$${cart.totalAmount}")
}
}总结
本章详细介绍了 Scala 中类和对象的核心概念:
- 类定义:构造函数、字段、方法的定义
- 对象:单例对象和伴生对象的使用
- 案例类:自动生成有用方法的特殊类
- 继承:类的继承和方法重写
- 特征:多重继承和混入机制
- 访问修饰符:控制成员的可见性
- 实际应用:银行系统、图形系统等实例
掌握这些面向对象编程概念是构建复杂 Scala 应用的基础。在下一章中,我们将学习 Scala Trait 特征,深入了解 Scala 独特的特征系统和混入机制。