问题理解
提出问题:当多人开发时,如果有几个人定义的几个类的类名一样时,此时该怎么解决?【同名报错】
解决办法:将同名的几个类放在不同的包下(实际是创建不同的文件夹来保存源代码文件)
包的作用:
- 区分相同名字的类
- 更好地管理项目
- 控制类的访问范围
命名规则
- 只能包含数字、字母、下划线、小圆点
- 不能数字开头;不能使用关键字
规范:一般是小写字母 + 小圆点
一般写法:com.公司名.项目名.业务模块名
举例:com.microsoft.sheet.service
打包的三种形式
// 形式1
package com.ymk.service
// 形式2:和形式1等价
package com.ymk
package service
// 形式3:注意事项
package com.ymk {
package service {
// ......
}
}
📝 注意事项(形式3)
👉 1. 包的嵌套问题
- 包可以嵌套使用,也可以嵌套类、特质等内容
- 优点:可以在同一个文件中将不同的内容创建在不同的包中,非常灵活
- 注意:在同一个源文件中,可以声明多个并列的包,但是嵌套的包不要超过3层
👉 2. 路径和包名的一致性
- Java 中包名和源文件所在路径要一致,编译后的字节码文件路径也会和包名保持一致
- Scala 中包名和源文件所在路径可以不一致,但是编译后的字节码文件路径会和包名保持一致(该工作由编译器完成)
👉 3. 作用域原则
- 可以向上访问,即子包可以直接访问父包中的内容,大括号体现作用域
- 父包访问子包内容时,需要导入对应的类或者写完整的类名
- 注意:在子包和父包中,类重名时,默认采用就近原则,否则请带上包名,指定具体的类名
区别:Java 中子包使用父包中的类,需要导入,而 Scala 不需要
包对象
包可以包含类、对象和特质,但不能包含变量、方法的定义
包对象可以包含变量、方法,也可以包含类、对象等// 文件所在包:com.scala.clazz,即源文件在xxx/com/scala/clazz目录下
package com.scala {
package clazz { // 路径:xxx/com/scala/clazz
object Package {
def main(args: Array[String]): Unit = {
val u1: User = new User
val u2 = new com.scala.clazz.util.User()
print(s"$u1\n$u2")
}
}
class User {
var name: String = "clazz -> User"
override def toString: String = this.name
}
class Employee {
var name: String = "clazz -> Employee"
override def toString: String = this.name
}
// 包对象
package object util {
var name: String = "king"
def sayHi(): Unit = {
println("Hi~~~")
}
}
package util { // 路径:xxx/com/scala/clazz/util
class User {
var name: String = "clazz -> util -> User"
val employee = new Employee
// 使用包对象中的变量和方法
println(util.name)
sayHi()
// 重写 toString 方法
override def toString: String = this.name + " | " + this.employee
}
}
}
}
📝 详情说明
每个包只能有一个包对象,如上述代码中的“util”包
- 包对象的名字要和包名字一样
- 在包对象中可以定义变量、方法
- 在包中可以使用包对象中定义的变量和方法等
✍ 底层原理package.javapackage$.java
- 包对象在底层会生成 package.class 和 package$.class 两个字节码文件
- 通过 package$ 的一个静态实例完成对包对象中的属性和方法的调用
可见性⭐
Java
| 访问级别 | 访问控制修饰符 | 同类 | 同包 | 子类 | 不同包 | | :—-: | :—-: | :—-: | :—-: | :—-: | :—-: | | 公开 | public | ✔️ | ✔️ | ✔️ | ✔️ | | 受保护 | protected | ✔️ | ✔️ | ✔️ | ❌ | | 默认 | 没有修饰符 | ✔️ | ✔️ | ❌ | ❌ | | 私有 | private | ✔️ | ❌ | ❌ | ❌ |
📝 说明
- 修饰符可以修饰类中的属性、方法、类
-
Scala
1️⃣ 属性
访问权限为默认,从底层看,属性定义时是 private,任意地方可访问【因为底层提供了 **xxx/xxx$eq_ 方法**】
- 访问权限为 private,表示私有的,只能在类的内部和伴生对象中访问【因为底层 **xxx/xxx$eq_ 方法是私有的**】
2️⃣ 方法
- 访问权限为默认,从底层看,方法是 public 的
- 访问权限为 private,表示私有的,只能在类的内部和伴生对象中访问
3️⃣ 公共
- Scala 中受保护权限(protected)比 Java 中更严格,只能子类访问,同包不能访问
- Scala 中没有 public 关键字,不能使用 public 显式地修饰属性和方法
- 包访问权限,对属性做限制的同时,对包也进行限制,语法“private|protected[包名] var xxx = yyy”
📝 总结:Scala 中一共四种权限:默认的、受保护的、私有的、包访问权限
// 自行测试
package com.scala
object Test {
def main(args: Array[String]): Unit = {
val p1 = new Person("zhangsan")
println(p1.age)
Person.test(p1)
}
}
class Person(pName: String) {
var name: String = pName
// 包访问权限
// private 起作用,同类、com.scala包下的其他类都可以使用
private[scala] var age: Int = 12
private def show(): Unit = {
println("show: " + s"name=$name, age=$age")
}
}
包的引入
引入语法:import xxx.yyy
自动引入的包有三个:
- java.lang 包
- scala 包
- Predef 包
出现的位置:import 语句可以出现在任何地方,作用范围是整个代码块;这样做的好处是,只在需要时引入,缩小了引入包的作用范围,提高效率
📝 导入说明
- 如果想要导入包中所有类,可以使用“_”,Java 中使用“*”
- 比如:import **scala.io.**_
- 如果只导入包中的几个类,可以使用“{}”
- 比如:import scala.collection.mutable.{HashMap, HashSet}
- 如果导入的多个包中有同名的类,可以将类的名字进行重命名
- 比如:import scala.collection.mutable.{HashMap => JavaHashMap, HashSet}
- 如果某个冲突的类根本不会用到,可以在导入时将其隐藏
- 比如:import java.util.{HashMap => , }【引入所有,只忽略HashMap】