Scala编程基础6:Scala访问修饰符
Scala的访问修饰符基本和Java的一样,分别有:private、protected和public。如果没有指定访问修饰符,默认情况下,Scala对象的访问权限都是public权限。Scala中的private修饰符,比Java更严格:在嵌套类情况下,Scala外部类不能访问内部类的private成员,Java中是允许外部类访问内部类的private成员的。
1.Private修饰符
在一个类中,使用private修饰符修饰的成员只在包含了成员定义的类或者对象内部可见,同样的规则还适用于内部类。就是说,内部类可以访问外部类的所有成员,包括private成员;但是外部类却不能访问内部类的private成员,例如:
编辑一个ClassA.scala的文本文件,内容如下:
class ClassA {
class ClassB {
private def funB() { println("Hello ClassB"); }
class ClassC {
funB();//正确
}
}
(new ClassB).funB();//错误
}
使用scalac命令编译ClassA.scala文件将报如下错误:
E:\Scala>scalac ClassA.scala
ClassA.scala:10: error: method funB in class ClassB cannot be accessed in ClassA.this.ClassB
(new ClassB).funB();
^
one error found
上述例子中,ClassB中定义了一个private成员方法funB,用来打印一句话。ClassB的funB方法在其内部类ClassC中是可以正确访问的;但是在其外部类ClassA中访问是没有权限的,编译出错。Java中允许这两种访问,因为Java允许外部类访问内部类的private成员。
2.Protected修饰符
在Scala中,对protected成员的访问也比Java更严格:Scala中只允许protected成员在该类中及其子类中被访问;而在Java中,protected成员除了可以在该类中及其子类中被访问,还可以在该类所在包下的其他类中被访问。例如:
编辑一个Super.scala的文本文件,内容如下:
package p {
class Super {
protected def fun() {println("Hello Super");}
}
class Sub extends Super {
fun();//OK
}
class Other {
(new Super).fun();//error
}
}
使用scalac命令编译Super.scala文件将报如下错误:
E:\Scala>scalac Super.scala
Super.scala:9: error: method fun in class Super cannot be accessed in p.Super
Access to protected method fun not permitted because
enclosing class Other in package p is not a subclass of
class Super in package p where target is defined
(new Super).fun();
^
one error found
在上述例子中,子类Sub对父类Super中的fun方法的访问没有问题,但是其他类Other对fun方法的访问却没有权限,因为Other类没有继承自Super。但是在Java中这两种访问都是可以的。
3.Public修饰符
在Scala类中,如果没有指定任何修饰符,默认的修饰符是public。public成员在任何地方都可以被访问。例如:
修改第一个例子中的ClassA.scala文件,去掉funB方法前面的private修饰符,即将funB改成public权限,内容如下:
class ClassA {
class ClassB {
def funB() { println("Hello ClassB"); }
class ClassC {
funB();//正确
}
}
(new ClassB).funB();//正确
}
使用scalac命令编译ClassA.scala文件将顺利通过:
E:\Scala>scalac ClassA.scala
上述例子中,ClassB中funB方法为public权限,在其内部类ClassC中是可以正确访问的,在其外部类ClassA中也能正确访问。
4.作用域保护
在Scala中,可以使用访问修饰符来限定作用域,格式如下:
private[x]
或
protected[x]
这里的x指代某个所属的包、类或单例对象。例如:如果使用private[x]来修饰一个成员,则表示”这个成员除了对[…]中的类(此时x是一个类)或[…]中的包中的类(此时x是一个包)及它们的伴生对像可见外,对其它所有类都是private。这同样适用于protected[x]。
这种技巧在横跨了若干包的大型项目中非常有用,它允许你定义一些在你项目的若干子包中可见但对于项目外部的客户却始终不可见的东西。
package bobsrocckets {
package navigation {
private[bobsrockets] class Navigator {
protected[navigation] def useStarChart() {}
class LegOfJourney {
private[Navigator] val distance = 100
}
private[this] var speed = 200
}
}
package launch {
import navigation._
object Vehicle {
private[launch] val guide = new Navigator
}
}
}
上述例子中,类Navigator被标记为private[bobsrockets],虽然该类在子包navigation 中,但是它的有效范围却是外部包bobsrockets的范围,即对外部包bobsrockets中的所有的子包、类和对象可见。比如可以在包bobsrockets的另一个子包launch中的类Vehicle中使用Navigator类。但是,所有在包bobsrockets之外的所有的包、类和对象都不能访问类Navigator。上述例子中的其他限定作用域同理分析即可。