1. 概述
在本篇文章中,我们将深入探讨 Scala 中的 包(Package)、导入(Import) 以及 包对象(Package Object) 的使用方式。
我们会看到不同形式的类型导入方法、包的定义方式,以及一些强大的包特性,这些特性在实际开发中非常实用。
2. Scala 中的导入机制
导入语句用于将所需的类或类型引入当前文件的作用域内。下面我们来了解几种常见的导入方式。
2.1. 基础导入
✅ 单个类的导入非常直观,和 Java 类似:
import com.baeldung.scala.packageimport.vehicle.Bicycle
如果要导入某个包下的所有类,可以使用通配符 _
:
import com.baeldung.scala.packageimport.vehicle._
也可以在一行中显式指定多个类进行导入:
import com.baeldung.scala.packageimport.vehicle.{Bicycle, Car, Vehicle}
2.2. 别名导入
有时候我们可能会遇到从不同包中导入同名类的情况,比如:
import java.util.Date
import java.sql.Date
这两个 Date
类返回的时间格式不同:
java.sql.Date
只显示日期java.util.Date
显示日期和时间
为了避免命名冲突,我们可以使用别名导入:
import java.util.{Date => utilDate}
import java.sql.{Date => sqlDate}
之后就可以像普通变量一样使用它们了:
def run(): Unit = {
val dt: utilDate = new utilDate()
val dtSql: sqlDate = new sqlDate(System.currentTimeMillis())
println(s"I am a vehicle running on $dt !")
println(s"I am a vehicle running on $dtSql !")
}
输出示例:
I am a vehicle running on Wed May 27 13:50:53 CEST 2020 !
I am a vehicle running on 2020-05-27 !
2.3. 导入时隐藏特定类
有时候我们想导入一个包中的所有类,但排除其中某一个类。例如,只隐藏 java.util.Date
:
import java.util.{Date => _, _}
import java.sql.Date
这样我们就可以放心使用 java.sql.Date
而不用担心冲突:
override def run(): Unit = {
super.run()
val dtSql: Date = new Date(System.currentTimeMillis())
println(s"$numberOfTires tires from the bicycle brand $brand are running on $dtSql")
}
3. Scala 中的包定义方式
Scala 提供了多种灵活的方式来定义包结构。
3.1. 简单包定义
和 Java 一样,在类文件顶部声明包名即可:
package com.baeldung.scala
package object packageimport {
trait Motor {
val dieselMessage: String = "I am not environment friendly"
val noDieselMessage: String = "I am environment friendly"
}
}
3.2. 在同一文件中定义多个包
通过大括号 {}
,我们可以在一个文件中定义多个包,并且每个包中可以有相同名称的类:
package com.baeldung.scala.packageimport.vehicle {
import java.util.{Date => utilDate}
import java.sql.{Date => sqlDate}
abstract class Vehicle(numberOfTires: Int, brand: String) {
def run(): Unit = {
val dt: utilDate = new utilDate()
val dtSql: sqlDate = new sqlDate(System.currentTimeMillis())
println(s"I am a vehicle running on $dt !")
println(s"I am a vehicle running on $dtSql !")
}
}
}
package com.baeldung.scala.packageimport.vehicleNew {
import java.sql.{Date => sqlDate}
abstract class Vehicle(numberOfTires: Int, brand: String) {
def run(): Unit = {
val dtSql: sqlDate = new sqlDate(System.currentTimeMillis())
println(s"I am a NEW vehicle running on $dtSql !")
}
}
}
此时两个 Vehicle
类分别属于不同的包,可通过完整路径访问:
com.baeldung.scala.packageimport.vehicle.Vehicle
com.baeldung.scala.packageimport.vehicleNew.Vehicle
3.3. 包堆叠(Package Stacking)
我们可以连续写多个包声明,实现“包堆叠”效果。这相当于嵌套包的简写方式:
package com.baeldung.scala
package packageimport
package stacking
等价于:
package com.baeldung.scala.packageimport.stacking
⚠️ 但好处是:可以直接访问前面每一层包中的类,无需额外导入。
也就是说,不需要再写 import com.baeldung.scala._
就能直接使用该包下的类。
4. 包对象(Package Object)
✅ 包对象允许我们将方法、函数、变量等顶级成员绑定到某个包上,供该包的所有子成员共享。
每个包只能有一个包对象,通常命名为 package.scala
,并放置在对应包目录下。
举个例子,为 packageimport
包创建一个包对象:
package com.baeldung.scala
package object packageimport {
val year = "2020"
trait Motor {
val dieselMessage: String = "I am not environment friendly"
val noDieselMessage: String = "I am environment friendly"
}
}
在这个包下的所有类都可以直接访问 year
和 Motor
,无需显式导入包对象:
object bmwB38 extends Motor {
def run(): Unit =
println(s"I am a bmwB38 ! $noDieselMessage")
}
5. 总结
本文我们系统地讲解了 Scala 中的导入语法、包的定义方式,以及包对象的强大功能。
主要收获包括:
✅ 不同的导入方式及其适用场景
✅ 如何处理同名类冲突问题
✅ 多种包定义方式及各自特点
✅ 包对象如何简化顶级成员共享
最后,别忘了代码都在 GitHub 上:https://github.com/Baeldung/scala-tutorials/tree/master/scala-lang-modules/scala-lang