一、类(Class):面向对象的核心载体
类是 Scala 中描述「对象属性和行为」的模板,用于创建具体的实例(对象)。Scala 的类相比 Java 更简洁,支持参数化构造、默认值、方法简化等特性。
1. 类的基本定义与实例化
// 定义一个简单的类:包含属性(name/age)和方法(greet)
class Person(name: String, age: Int) { // 主构造器参数(直接写在类名后)
// 类体:可以定义方法、属性、代码块
def greet(): String = s"Hello, I'm $name, $age years old."
// 定义类的字段(用val/var修饰,对外可访问;无修饰则仅类内可见)
val fullName: String = name // 不可变字段(val)
var currentAge: Int = age // 可变字段(var)
}
// 实例化类(创建对象):无需 new 关键字(Scala 2.13+ 支持,旧版本需加 new)
val person1 = new Person("Alice", 25) // 推荐写法(兼容所有版本)
val person2 = Person("Bob", 30) // Scala 2.13+ 简化写法
// 访问对象的属性和方法
println(person1.fullName) // 输出:Alice
println(person1.currentAge) // 输出:25
println(person1.greet()) // 输出:Hello, I'm Alice, 25 years old.
// 修改可变字段
person1.currentAge = 26
println(person1.currentAge) // 输出:26
2. 类的构造器(核心特性)
Scala 类有三种构造器,核心是主构造器,辅助构造器为补充:
(1)主构造器
- 直接写在类名后的参数列表(
class Person(name: String, age: Int))。 - 类体中的所有非方法 / 非字段代码,都会作为主构造器的执行逻辑。
- 支持参数默认值、访问修饰符(
private/public)。
// 带默认值的主构造器
class Student(name: String = "Unknown", var score: Double = 0.0) {
// 主构造器执行代码(创建实例时会执行)
println(s"Student $name created, score: $score")
def getGrade: String = {
if (score >= 90) "A"
else if (score >= 80) "B"
else "C"
}
}
// 实例化:省略参数则使用默认值
val stu1 = new Student("Charlie", 95.5) // 输出:Student Charlie created, score: 95.5
val stu2 = new Student() // 输出:Student Unknown created, score: 0.0
println(stu1.getGrade) // 输出:A
(2)辅助构造器
- 用
def this(...)定义,必须直接 / 间接调用主构造器(第一行代码)。 - 用于提供多套实例化参数方案。
class User(username: String, email: String) {
// 辅助构造器1:仅传用户名,邮箱用默认值
def this(username: String) = this(username, s"$username@default.com")
// 辅助构造器2:无参数,全用默认值
def this() = this("guest")
def showInfo: String = s"Username: $username, Email: $email"
}
// 用不同构造器实例化
val user1 = new User("alice123", "alice@test.com")
val user2 = new User("bob456")
val user3 = new User()
println(user1.showInfo) // 输出:Username: alice123, Email: alice@test.com
println(user2.showInfo) // 输出:Username: bob456, Email: bob456@default.com
println(user3.showInfo) // 输出:Username: guest, Email: guest@default.com
3. 类的访问修饰符
Scala 支持 private/protected/public(默认 public),且支持更精细的访问控制:
class Employee(private val id: String, var name: String) {
// private 方法:仅类内可调用
private def checkId: Boolean = id.nonEmpty
// 公共方法:对外暴露逻辑
def validate: String = {
if (checkId) s"Employee $name is valid"
else "Invalid employee ID"
}
}
val emp = new Employee("E123", "David")
println(emp.name) // 可访问(public)
// println(emp.id) // 编译报错(private)
// println(emp.checkId) // 编译报错(private)
println(emp.validate) // 输出:Employee David is valid
二、对象(Object):Scala 的单例与工具载体
Scala 没有 static 关键字,而是通过 object 实现单例、静态方法 / 属性、工具类等功能,主要分为单例对象和伴生对象。
1. 单例对象(Standalone Object)
- 用
object定义,全局唯一实例(JVM 加载时自动创建)。 - 常用于定义工具方法、常量、程序入口(
main方法)。
// 定义单例对象(工具类)
object MathUtils {
// 常量(相当于 Java 的 static final)
val PI: Double = 3.1415926
// 工具方法(相当于 Java 的 static 方法)
def circleArea(radius: Double): Double = PI * radius * radius
// 程序入口(main 方法必须定义在 object 中)
def main(args: Array[String]): Unit = {
println(s"PI = $PI")
println(s"Circle area (r=2): ${circleArea(2)}") // 输出:12.5663704
}
}
// 调用单例对象的属性/方法(无需实例化)
println(MathUtils.PI) // 输出:3.1415926
println(MathUtils.circleArea(3)) // 输出:28.2743334
2. 伴生对象(Companion Object)
- 与类同名、同文件的
object,称为该类的伴生对象;对应的类称为伴生类。 - 伴生对象和伴生类可以互相访问对方的
private成员(核心优势)。 - 常用于定义工厂方法(简化类的实例化)、隐式转换等。
// 伴生类(普通类)
class Person private (val name: String, val age: Int) { // 主构造器私有化
private def secret: String = "I love Scala"
}
// 伴生对象(与类同名、同文件)
object Person {
// 工厂方法:简化实例化(对外隐藏构造器细节)
def apply(name: String): Person = new Person(name, 18) // 访问私有构造器
def apply(name: String, age: Int): Person = new Person(name, age)
// 访问伴生类的私有方法
def getSecret(person: Person): String = person.secret
}
// 用伴生对象的 apply 方法实例化(无需 new)
val p1 = Person("Alice") // 等价于 Person.apply("Alice")
val p2 = Person("Bob", 25) // 等价于 Person.apply("Bob", 25)
println(p1.name) // 输出:Alice
println(Person.getSecret(p1)) // 输出:I love Scala(访问私有方法)
// val p3 = new Person("Charlie", 30) // 编译报错(构造器私有化)
关键:apply 方法的特殊作用
伴生对象中的 apply 方法是 Scala 的语法糖:
- 调用
Person(参数)等价于调用Person.apply(参数)。 - 无需写
new,让类的实例化像调用函数一样简洁,是 Scala 集合(如List(1,2,3))的核心实现方式。
3. 扩展:case class 与伴生对象
case class(样例类)是 Scala 特有的便捷类,自动生成伴生对象、apply 方法、equals/hashCode 等,常用于数据封装:
// 定义样例类(自动生成伴生对象、apply方法、toString等)
case class Book(title: String, author: String, price: Double)
// 实例化(无需 new,自动调用伴生对象的 apply 方法)
val book1 = Book("Scala编程", "Martin Odersky", 89.0)
val book2 = Book("Java编程思想", "Bruce Eckel", 108.0)
// 自动生成 toString 方法
println(book1) // 输出:Book(Scala编程,Martin Odersky,89.0)
// 自动生成 equals 方法(值比较,而非引用比较)
val book3 = Book("Scala编程", "Martin Odersky", 89.0)
println(book1 == book3) // 输出:true
三、类的继承(Inheritance)
Scala 支持单继承(extends),通过 override 重写父类方法 / 属性,核心规则:
- 父类构造器必须在子类中被调用(写在
extends后)。 - 重写方法 / 属性必须加
override关键字。 final修饰的类 / 方法不能被继承 / 重写。
// 父类(基类)
class Animal(name: String) {
def makeSound: String = "Some sound"
val category: String = "Animal"
}
// 子类(继承 Animal)
class Dog(name: String) extends Animal(name) { // 调用父类构造器
// 重写父类方法
override def makeSound: String = "Woof Woof"
// 重写父类属性
override val category: String = "Dog"
}
// 测试
val dog = new Dog("Buddy")
println(dog.name) // 输出:Buddy(继承父类属性)
println(dog.makeSound) // 输出:Woof Woof(重写方法)
println(dog.category) // 输出:Dog(重写属性)
四、抽象类(Abstract Class)
抽象类用 abstract 修饰,包含未实现的抽象方法 / 属性,不能直接实例化,需子类实现抽象成员:
// 抽象类
abstract class Shape {
// 抽象属性(无初始值)
val color: String
// 抽象方法(无实现)
def area: Double
}
// 子类实现抽象类
class Circle(color: String, radius: Double) extends Shape {
// 实现抽象属性
override val color: String = color
// 实现抽象方法
override def area: Double = Math.PI * radius * radius
}
val circle = new Circle("Red", 2.0)
println(circle.color) // 输出:Red
println(circle.area) // 输出:12.566370614359172
总结
-
类(Class) :是创建实例的模板,主构造器写在类名后,辅助构造器用
def this定义,支持访问修饰符和继承。 -
对象(Object) :
- 单例对象:全局唯一实例,用于工具方法、常量、程序入口(
main)。 - 伴生对象:与类同名同文件,可访问类的私有成员,
apply方法简化实例化。
- 单例对象:全局唯一实例,用于工具方法、常量、程序入口(
-
核心语法糖:
case class自动生成伴生对象、apply/equals等方法,适合数据封装。- 伴生对象的
apply方法让类实例化像调用函数一样简洁。
-
继承规则:Scala 单继承,重写需加
override,抽象类需子类实现抽象成员。