一、类(Class):对象的模板
类是 创建对象的蓝图,定义了对象的属性(成员变量)和行为(成员方法)。Scala 中的类支持:构造器(主构造器 + 辅助构造器)、继承、封装、多态等 OOP 特性,同时简化了语法(如自动生成 getter/setter)。
1. 基本定义与实例化
// 定义类:主构造器直接写在类名后(参数列表可选)
class Person(name: String, var age: Int) { // name: 私有不可变(无var/val);age: 公有可变(var)
// 类体:初始化逻辑、成员方法、辅助构造器等
println(s"创建 Person 实例:$name, $age") // 主构造器执行时会运行类体中的语句
// 成员方法
def introduce(): String = s"我是 $name,今年 $age 岁"
// 辅助构造器(必须调用主构造器或其他辅助构造器,以 this 开头)
def this(name: String) = this(name, 18) // 无年龄时默认18岁
}
// 实例化类(无需 new 关键字,Scala 2.13+ 支持;低版本需加 new)
val p1 = new Person("张三", 25) // 输出:创建 Person 实例:张三, 25
val p2 = Person("李四") // 调用辅助构造器,默认年龄18
// 访问成员
println(p1.age) // 25(var 修饰的属性可直接访问,自动生成 setter)
p1.age = 26 // 修改 age(var 生成 setter)
// println(p1.name) // 编译报错:name 无 var/val 修饰,默认是私有成员,仅类内部可访问
println(p1.introduce()) // 输出:我是 张三,今年 26 岁
2. 类的核心特性
| 特性 | 说明 |
|---|---|
| 主构造器 | 类名后的参数列表(class A(a: Int, val b: String)),类体中无函数体的代码均为主构造器逻辑 |
| 字段修饰符 | - 无 var/val:私有不可变(仅类内部访问)- val:公有不可变(仅生成 getter)- var:公有可变(生成 getter + setter) |
| 辅助构造器 | 用 def this(...) 定义,必须先调用主构造器(this(...))或其他辅助构造器 |
| 私有成员 | 用 private 修饰(默认私有范围是类和伴生对象),private[this] 仅当前实例可访问 |
| 继承 | 用 extends 继承类,子类必须调用父类构造器;重写方法需加 override 关键字 |
示例:继承与重写
// 父类
class Animal(val name: String) {
def makeSound(): String = "未知叫声"
}
// 子类(继承 Animal,必须调用父类构造器)
class Dog(name: String) extends Animal(name) {
override def makeSound(): String = "汪汪汪" // 重写方法必须加 override
}
val dog = Dog("旺财")
println(dog.name) // 继承自父类的 val 字段,可访问
println(dog.makeSound()) // 输出:汪汪汪
二、对象(Object):单例与工具容器
Scala 中没有 static 关键字,对象(Object) 承担了两种核心角色:单例对象 和 伴生对象。对象是 懒加载的单例实例(首次访问时初始化,全局唯一)。
1. 单例对象(独立对象)
独立于类的对象,本质是全局唯一的实例,常用于:工具类、常量定义、程序入口(main 方法)。
// 单例对象:工具类(全局唯一,无需实例化)
object MathUtils {
// 常量(用 val 定义,类似 Java 的 static final)
val PI: Double = 3.1415926
// 工具方法(类似 Java 的 static 方法)
def circleArea(radius: Double): Double = PI * radius * radius
}
// 直接通过对象名访问,无需 new
println(MathUtils.PI) // 3.1415926
println(MathUtils.circleArea(2)) // 12.5663704
// 程序入口:Scala 程序的 main 方法必须定义在单例对象中
object HelloWorld {
def main(args: Array[String]): Unit = {
println("Hello, Scala!")
}
}
2. 伴生对象(Companion Object)
与某个类同名的对象,称为该类的 伴生对象;对应的类称为 伴生类。两者必须定义在同一个源文件中,核心特性:相互访问私有成员(无需 getter/setter)。
伴生对象的典型用途:
- 替代 Java 的
static方法 / 常量(如工厂方法、静态工具) - 与伴生类共享私有状态
// 伴生类(Class)
class Student(private val id: Int, val name: String) {
def printId(): Unit = {
// 伴生类可访问伴生对象的私有成员
println(s"学生ID:$id,学校:${Student.SCHOOL_NAME}")
}
}
// 伴生对象(Object,与类同名)
object Student {
// 私有常量(仅伴生类和伴生对象可访问)
private val SCHOOL_NAME: String = " Scala 大学"
// 工厂方法(替代 new,灵活创建实例)
def apply(name: String): Student = new Student(generateId(), name)
// 私有工具方法(仅伴生类和伴生对象可访问)
private def generateId(): Int = scala.util.Random.nextInt(1000)
}
// 使用伴生对象的工厂方法创建实例(无需 new)
val s1 = Student("王五") // 调用 apply 方法,等价于 Student.apply("王五")
s1.printId() // 输出:学生ID:xxx(随机数),学校:Scala 大学
// 伴生对象可访问伴生类的私有成员
val s2 = new Student(1001, "赵六")
// println(s2.id) // 编译报错:id 是伴生类的私有成员,外部不可访问
// 但伴生对象可访问(需通过实例)
object StudentHelper {
def getStudentId(student: Student): Int = student.id // 编译报错:StudentHelper 不是伴生对象,无法访问私有 id
}