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)中测试不同修饰符,观察访问错误。
  • 函数式编程:优先使用 privateprivate[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] 或包作用域)或更多示例,请告诉我!

类似文章

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注