4.Scala的包和导入
4.1 包
包以关键字package
开头,可以用花括号把包的范围括起来,这样一个文件可以包含多个不同的包;也可以不用花括号,这样包的声明必须在最前面,表明整个文件的内容都属于这个包。对于包的命名方法,可以使用反转域名法,即com.xxx.xxx
。在包中可以定义class,object和trait,也可以定义别的package。编译一个包文件,会在当前路径下生成一个与包名相同的文件夹,文件夹中是包内class,object和trait的编译后生成的文件,或者包内更深一层的文件夹。如果多个文件的顶层包的包名相同,编译后的文件会放在同一个文件夹内。一个包的定义可以由多个文件的源代码组成,包名和源文件所在路径不一定相同。
4.2 包的层次和精确代码访问
包中可以定义包,所以包也有层次结构。包可以通过句点符号按路径层次访问,如果包中出现了句点,那么编译器会按层次编译。
package one.two
等效于
package onepackage two
这样会先编译出一个名为one的文件夹,在里面再编译出一个名为two的文件夹。下面这段代码展示了使用包的一个实例:
package bobsrockets {package navigation {class Navigator {val map = new StarMap}class StarMap}class Ship {val nav = new navigation.Navigator}package fleets {class Fleet {def addShip() = { new Ship }}}
}
- 访问同一个
package
内的class,object,trait不需要增加路径前缀。 - 访问同一个包内更深一层的包所包含的class,object,trait,只需要写出更深的那一层包。在这里
class Ship
和package navigation
是同级的,所以访问navigation包中的class,object,trait只需要写navigation.
- 使用花括号表示包的作用范围时,包外所有可访问的class、object、trait在包内也可以直接访问。
以上规则在同一个文件内显式嵌套才可以生效,如果包分散在多个文件中,通过包名带句点来嵌套,则无法生效。
在同一个文件中如果存在两个同级别的包,则第二个包要加花括号,包括第二个包的字包都要加花括号。Scala还定义了一个隐式的顶层包_root_
,它是所有自定义的包的顶层包。
4.3 import导入
Scala的import很灵活,体现在以下三点:
- 可以出现在代码的任意位置;
- 除了导入包内所有内容,还可以导入对象(单例对象和new构造的对象都可以)和包自身,甚至函数的参数也可以当作对象来导入;
- 可以重命名或隐藏某些成员。
package A {package B {class M}package C {object N}
}
假设有上面的一段代码,通过import A.B
就能把包B导入,访问M时只需写B.M即可。通过import A.B.M
和import A.C.N
分别导入了类M和对象N,访问它们只需要写M和N即可。
可以通过import A.{B,C}
导入两个包,也可以使用import A._
或import A{_}
达到相同的效果。
如果写成import A.{B=>packageB}
就是在导入包B的同时重命名为packageB
,此时可以用packageB指代包B,也可以用A.B访问。如果写成import A.{B=>_,_}
就是把包B进行隐藏,而导入A的其他元素。
4.4 自引用
Scala中用关键字this
指代对象自己,如果this用在类的方法中,则指代正在调用方法的那个对象,如果用在类的构造方法中,则指代当前正在构建的对象。
4.5 访问修饰符
包、类和对象的成员都可以标上访问修饰符private
和protected
,用private
修饰的成员是私有的,只能被包含它的包,类或对象的内部代码访问;用protected
修饰的成员是受保护的,除了能被包含它的包,类或对象的内部代码访问,还能被子类访问。
除此之外,还可以加入限定词,private[X]
和protected[X]
就是在加限定词的基础上,把访问权限扩大到X的内部。限定词还可以是this,private[this]
比private
更严格,不仅只能由内部代码访问,而且只能在当前对象内部访问,还必须是调用方法的对象或构造方法正在构造的对象来访问,protected[this]
在此基础上扩展到定义时的子类。换句话说,private[this]
和protected[this]
修饰的成员x,只能用this.x
访问。
伴生对象和伴生类共享访问权限,两者可以互访对方的所有私有成员。在伴生对象中使用protected
没有意义,特质使用private
和protected
也没有意义。
4.6 包对象
包中可直接包含的元素有类、特质和单例对象,但其实类内可定义的元素都能放在包中,只是字段和方法不能直接定义在包中。Scala把字段和方法放在一个“包对象”中,每个包都允许有一个包对象。包对象使用关键字组合package object
来定义,其名称与关联的包名相同,类似伴生类和伴生对象的关系。