快学Scala第7章—–包和引入
本章要点
- 包也可以像内部类那样嵌套
- 包路径不是绝对路径
- 包声明链x.y.z并不自动将中间包x和x.y变成可见
- 位于文件顶部不带花括号的包声明在整个文件范围内有效
- 包对象可以持有函数好变量
- 引入语句可以引入包、类和对象
- 引入语句可以出现在任何位置
- 引入语句可以重命名和隐藏特定成员
- java.lang、scala和Predef总是被引入
包
要增加条目到包中:
package com {
package horstmann {
package impatient {
class Employee
...
}
}
}
这样你就可以在任意的地方以com.horstman.impatient.Employee访问到了Employee类。 与对象或这类的定义不同,同一个包可以定义在多个文件中。
作用域规则
Scala的包和其他作用域一样的支持嵌套,你可以访问上层作用域中的名称:
package com {
package horstman {
object Utils {
def percentOf(value: Double, rate: Double) = value * rate / 100
...
}
}
package impatient {
class Employee {
...
def giveRise(rate: Double) {
salary += Utils.percentOf(salary, rate)
}
}
}
}
在不同的文件中定义一个包,可能会出现一个问题:两个文件在定义包时覆盖了正确的包;
// 在一个文件中
package com {
package horstmann {
package impatient {
class Manager {
val subordinates = new collection.mutable.ArrayBuffer[Employee]
...
}
}
}
}
// 在另一个文件中
package com {
package horstmann {
package collection {
...
}
}
}
由于Scala允许使用相对路径的包名,自定义了collection之后,在com的作用域中就会使用自定义的包,就会在自定义的包中找ArrayBuffer,这样是错误的。解决方法之一是使用绝对包名,以root开始:
val subordinates = new _root_.scala.collection.mutable.ArrayBuffer[Employee]
另一种做法是使用串联式包语句,例如:
package com.horstmann.impatient {
// com和horstmann的成员在这里不可见
class Manager {
val subordinates = new collection.mutable.ArrayBuffer[Employee]
...
}
}
现在com.horstmann.collection包不再能够以collection 访问到了。
文件顶部标记法
在文件的顶部使用package语句,不带花括号:
package com.horstmann.impatient
package people
class Person
...
// 这等同于
package com.horstmann.impatient {
package people {
class Person
...
// 直到文件末尾
}
}
因此,你可以直接引用com.horstmann.impatient包中的内容。
包对象
包可以包含类、对象和特质,但不能包含函数或变量的定义。每个包都可以有一个包对象,你需要在父包中定义它,且名称与子包一样:
package com.horstmann.impatient
package object people {
val defaultNmae = "John Q. Public"
}
package people {
class Person {
val name = defaultName // 从包中拿到的常量
}
...
}
在这里,使用defaultName时不需要加上限定词,因为它位于同一个包内。在其他地方,这个常量可以用com.horstmann.impatient.people.defaultNmae访问到。
在幕后,包对象被编译成带有静态方法和字段的JVM类,名为package.class,位于相应的包下。
包可见性
在Java中,没有被声明为public、private、protected的类成员在包含该类的包中可见。在Scala中可以通过修饰符达到同样的效果。
package com.horstmann.impatient.people
class Person {
private[people] def description = "A person whith name " + name // people包中可见
// 扩展至上层包可见
private[impatient] def description = "A person whith name " + name
}
引入
引入语句可以让你使用更短的名称:
import java.awt.Color
// 引入某个包的全部成员
import java.awt._ // 这与Java中的通配符'*'一样
// 你也可以引入类或对象的所有成员
import java.awt.Color._
val c1 = RED // Color.RED
val c2 = decode("#ff0000") // Color.decode
任何地方都可以声明引用
class Manager {
import scala.collection.mutable._
val subordinates = new ArrayBuffer[Employee]
...
}
重命名和隐藏方法
在Java和Scala中都有HashMap,用过两个都被引用了则会导致冲突。解决办法就是使用选取器,将某一个HashMap重命名或者干脆直接隐藏掉(前提是你不会使用到它)。
// 选取器
import java.awt.{Color, Font}
// 重命名某个成员
import java.util.{HashMap => JavaHashMap}
import scala.collection.mutable._
// 隐藏某个成员
import java.util.{HashMap => _, _}
import scala.collection.mutable._
隐式导入
每个Scala程序都隐式的以如下代码开始
import java.lang._
import scala._
import Predef._
scala这和引入会覆盖java.lang包中冲突的成员。