为何可从其他包通过伴生对象访问Scala包作用域类?
Scala包级私有访问规则疑问解答
问题场景
Quark.scala(包a)
package a object Quark { def apply(): Quark = new Quark() } private[a] class Quark { def foo(): String = "bar" }
可运行的Main.scala(包b)
package b object Main { def main(args: Array[String]): Unit = { val quark = Quark() println(quark.foo()) // 编译通过,可正常执行 } }
编译报错的Main.scala(包b)
package b object Main { def main(args: Array[String]): Unit = { val quark = new Quark() // 编译报错! println(quark.foo()) } }
规则解析
你困惑的核心是没分清private[a]的作用范围边界:
private[a] class Quark限制的是类的构造权限和类本身的直接可见性:只有包a内部的代码能直接执行new Quark(),也只有包a内可以直接引用Quark类型。- 但Quark类的
foo()方法是默认公共权限(Scala中无修饰符的成员为public),只要能合法拿到Quark的实例,不管实例来自哪个包,都能调用它的公共成员方法。
第一个Main代码能运行,是因为Quark()调用的是包a内伴生对象的apply()方法——这个方法属于包a范畴,有权限创建Quark实例,之后把实例返回给包b的代码。包b拿到实例后,调用公共的foo()完全符合规则。
第二个Main代码直接执行new Quark(),是在包b里尝试调用Quark的构造方法,违反了private[a]的构造权限限制,因此编译器报错。
关键规则总结
private[X]属于限定私有,X可以是包、类或对象:- 修饰类时,仅约束类的构造器访问和类的直接引用权限,不影响类的非私有成员的访问
- 修饰成员方法/字段时,才会限制该成员的访问范围
- 类的成员默认是公共的,只要持有类的实例,就能调用这些成员。
官方规则依据
Scala语言规范中对限定私有(Qualified Private)的定义:
标记为
private[C]的元素,仅能在C的定义范围内被访问。对于类的限定私有修饰,它约束的是类的构造和直接可见性,但类的非私有成员不受此约束——只要持有类的实例,就能调用这些成员。
内容的提问来源于stack exchange,提问作者kylemart
相关产品推荐
相关产品推荐

