Scala 访问修饰符
在 Scala 中,访问修饰符(Access Modifiers)用于控制类、对象、方法、字段等的访问权限,决定它们在哪些范围内可见或可被访问。Scala 的访问修饰符比 Java 更灵活,支持细粒度的访问控制,包括包级、类级、对象级等。以下是对 Scala 访问修饰符的中文讲解,内容简洁清晰,涵盖定义、类型、用法及注意事项,适合初学者理解。
1. 访问修饰符概述
- 定义:访问修饰符是用于限制代码元素(如类、方法、字段)访问权限的关键字或语法。
- 作用:保护数据封装,控制代码的可见性和可访问性,防止未经授权的访问或修改。
- 默认行为:Scala 中未显式指定访问修饰符时,默认为 public(公开访问)。
2. Scala 访问修饰符类型
Scala 提供了以下主要的访问修饰符和访问控制方式:
1. public
(默认访问)
- 定义:没有显式指定访问修饰符时,Scala 默认所有成员为
public
,可以被任意地方访问。 - 特点:无限制访问,适合对外公开的接口或方法。
- 示例:
class Person {
val name = "Alice" // 默认 public
def sayHello() = println("Hello")
}
object Demo {
def main(args: Array[String]): Unit = {
val p = new Person
println(p.name) // 输出: Alice
p.sayHello() // 输出: Hello
}
}
2. private
(私有)
- 定义:用
private
关键字声明,成员只能在定义它的类或对象内部访问。 - 特点:
- 外部类、子类或包无法访问。
- 常用于隐藏实现细节。
- 示例:
class Person {
private val secret = "Hidden"
def reveal() = println(secret) // 内部可访问
}
object Demo {
def main(args: Array[String]): Unit = {
val p = new Person
// println(p.secret) // 错误:secret 是 private
p.reveal() // 输出: Hidden
}
}
3. protected
(受保护)
- 定义:用
protected
关键字声明,成员可以在定义它的类及其子类中访问,但外部无法访问。 - 特点:
- 与 Java 不同,Scala 的
protected
仅限于类及其子类,不允许同包访问(除非显式指定包作用域)。 - 示例:
class Person {
protected val familyName = "Smith"
}
class Employee extends Person {
def show() = println(familyName) // 子类可访问
}
object Demo {
def main(args: Array[String]): Unit = {
val e = new Employee
e.show() // 输出: Smith
// println(e.familyName) // 错误:外部无法访问
}
}
4. 作用域限定访问(private[scope]
和 protected[scope]
)
- 定义:Scala 允许通过
private[scope]
或protected[scope]
指定访问范围,scope
可以是包、类或对象。 - 特点:
- 提供细粒度的访问控制,超越 Java 的简单
public
/private
/protected
。 - 常见作用域:
private[this]
:仅限当前对象实例访问(对象私有)。private[package]
:仅限指定包内访问。protected[package]
:指定包及其子类可访问。
- 示例:
package com.example
class Person {
private[example] val city = "Beijing" // com.example 包内可访问
private[this] val id = 123 // 仅当前对象实例可访问
def showId(other: Person) = println(id) // 可访问自己的 id
// def showOtherId(other: Person) = println(other.id) // 错误:id 是 private[this]
}
object Demo {
def main(args: Array[String]): Unit = {
val p = new Person
println(p.city) // 输出: Beijing(同包可访问)
// println(p.id) // 错误:id 是 private[this]
}
}
5. 伴生对象访问
- 定义:Scala 的伴生对象(
object
与同名class
在同一文件中)可以访问彼此的private
成员。 - 示例:
class Person {
private val secret = "Hidden"
}
object Person {
def reveal(p: Person) = println(p.secret) // 伴生对象可访问 private 成员
}
object Demo {
def main(args: Array[String]): Unit = {
val p = new Person
Person.reveal(p) // 输出: Hidden
}
}
3. 访问修饰符规则总结
修饰符 | 访问范围 |
---|---|
无修饰符(public ) | 任意地方可访问 |
private | 仅类或对象内部可访问 |
protected | 类及其子类可访问 |
private[this] | 仅当前对象实例可访问 |
private[package] | 指定包及其子包可访问 |
protected[package] | 指定包及其子类可访问 |
4. 注意事项
- 默认
public
:Scala 简化了访问控制,未显式声明修饰符时默认公开,减少样板代码。 - Scala 2 vs Scala 3:
- Scala 3 的访问修饰符规则与 Scala 2 基本一致,但语法更严格(如
private[this]
更明确)。 - Scala 3 强调类型安全,错误提示更友好。
- 与 Java 的差异:
- Scala 的
protected
不允许同包访问,需用protected[package]
。 - Scala 的
private[this]
提供对象级私有,Java 无此特性。 - 伴生对象:伴生对象与类之间的私有成员互访是 Scala 的独特特性,适合封装相关逻辑。
- 性能:访问修饰符在编译时检查,不影响运行时性能。
5. 实践示例
综合示例,展示不同访问修饰符的用法:
package com.example
class Person {
val name = "Alice" // 默认 public
private val secret = "Hidden" // 私有
protected val familyName = "Smith" // 受保护
private[this] val id = 123 // 对象私有
private[example] val city = "Beijing" // 包内可访问
def show() = println(s"Name: $name, Secret: $secret, Family: $familyName, ID: $id, City: $city")
}
class Employee extends Person {
def showFamily() = println(familyName) // 可访问 protected 成员
// def showSecret() = println(secret) // 错误:secret 是 private
}
object Person {
def reveal(p: Person) = println(p.secret) // 伴生对象可访问 private 成员
}
object Demo {
def main(args: Array[String]): Unit = {
val p = new Person
println(p.name) // 输出: Alice
println(p.city) // 输出: Beijing
// println(p.secret) // 错误:secret 是 private
// println(p.id) // 错误:id 是 private[this]
p.show() // 输出: Name: Alice, Secret: Hidden, Family: Smith, ID: 123, City: Beijing
val e = new Employee
e.showFamily() // 输出: Smith
Person.reveal(p) // 输出: Hidden
}
}
6. 学习建议
- 实践:在 Scala REPL 或 IDE(如 IntelliJ IDEA)中测试不同修饰符,观察访问错误。
- 函数式编程:优先使用
private
和private[this]
封装数据,减少外部依赖。 - 包结构:练习
private[package]
和protected[package]
,理解包级访问控制。 - 资源:
- 官方文档:https://www.scala-lang.org/
- Scala Exercises (https://www.scala-exercises.org/)
- 《Programming in Scala》by Martin Odersky
如果需要深入讲解某一修饰符(如 private[this]
或包作用域)或更多示例,请告诉我!