问题理解

提出问题:当多人开发时,如果有几个人定义的几个类的类名一样时,此时该怎么解决?【同名报错
解决办法:将同名的几个类放在不同的包下(实际是创建不同的文件夹来保存源代码文件)
包的作用:

  • 区分相同名字的类
  • 更好地管理项目
  • 控制类的访问范围

打包语法:package xxx.yyy

命名规则

  • 只能包含数字、字母、下划线、小圆点
  • 不能数字开头;不能使用关键字

规范:一般是小写字母 + 小圆点
一般写法:com.公司名.项目名.业务模块名
举例:com.microsoft.sheet.service

打包的三种形式

  1. // 形式1
  2. package com.ymk.service
  3. // 形式2:和形式1等价
  4. package com.ymk
  5. package service
  6. // 形式3:注意事项
  7. package com.ymk {
  8. package service {
  9. // ......
  10. }
  11. }

📝 注意事项(形式3)
👉 1. 包的嵌套问题

  • 包可以嵌套使用,也可以嵌套类、特质等内容
  • 优点:可以在同一个文件中将不同的内容创建在不同的包中,非常灵活
  • 注意:在同一个源文件中,可以声明多个并列的包,但是嵌套的包不要超过3层

👉 2. 路径和包名的一致性

  • Java 中包名和源文件所在路径要一致,编译后的字节码文件路径也会和包名保持一致
  • Scala 中包名和源文件所在路径可以不一致,但是编译后的字节码文件路径会和包名保持一致(该工作由编译器完成)

👉 3. 作用域原则

  • 可以向上访问,即子包可以直接访问父包中的内容,大括号体现作用域
  • 父包访问子包内容时,需要导入对应的类或者写完整的类名
  • 注意:在子包和父包中,类重名时,默认采用就近原则,否则请带上包名,指定具体的类名
  • 区别:Java 中子包使用父包中的类,需要导入,而 Scala 不需要

    包对象

    包可以包含类、对象和特质,但不能包含变量、方法的定义
    包对象可以包含变量、方法,也可以包含类、对象等

    1. // 文件所在包:com.scala.clazz,即源文件在xxx/com/scala/clazz目录下
    2. package com.scala {
    3. package clazz { // 路径:xxx/com/scala/clazz
    4. object Package {
    5. def main(args: Array[String]): Unit = {
    6. val u1: User = new User
    7. val u2 = new com.scala.clazz.util.User()
    8. print(s"$u1\n$u2")
    9. }
    10. }
    11. class User {
    12. var name: String = "clazz -> User"
    13. override def toString: String = this.name
    14. }
    15. class Employee {
    16. var name: String = "clazz -> Employee"
    17. override def toString: String = this.name
    18. }
    19. // 包对象
    20. package object util {
    21. var name: String = "king"
    22. def sayHi(): Unit = {
    23. println("Hi~~~")
    24. }
    25. }
    26. package util { // 路径:xxx/com/scala/clazz/util
    27. class User {
    28. var name: String = "clazz -> util -> User"
    29. val employee = new Employee
    30. // 使用包对象中的变量和方法
    31. println(util.name)
    32. sayHi()
    33. // 重写 toString 方法
    34. override def toString: String = this.name + " | " + this.employee
    35. }
    36. }
    37. }
    38. }

    📝 详情说明

  • 每个包只能有一个包对象,如上述代码中的“util”包

  • 包对象的名字要和包名字一样
  • 在包对象中可以定义变量、方法
  • 在包中可以使用包对象中定义的变量和方法等

✍ 底层原理package.javapackage$.java

  • 包对象在底层会生成 package.classpackage$.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 中一共四种权限:默认的、受保护的、私有的、包访问权限

  1. // 自行测试
  2. package com.scala
  3. object Test {
  4. def main(args: Array[String]): Unit = {
  5. val p1 = new Person("zhangsan")
  6. println(p1.age)
  7. Person.test(p1)
  8. }
  9. }
  10. class Person(pName: String) {
  11. var name: String = pName
  12. // 包访问权限
  13. // private 起作用,同类、com.scala包下的其他类都可以使用
  14. private[scala] var age: Int = 12
  15. private def show(): Unit = {
  16. println("show: " + s"name=$name, age=$age")
  17. }
  18. }

包的引入

引入语法:import xxx.yyy
自动引入的包有三个:

  1. java.lang 包
  2. scala 包
  3. Predef 包

出现的位置:import 语句可以出现在任何地方,作用范围是整个代码块;这样做的好处是,只在需要时引入,缩小了引入包的作用范围,提高效率


📝 导入说明

  • 如果想要导入包中所有类,可以使用“_”,Java 中使用“*”
    • 比如:import **scala.io.**_
  • 如果只导入包中的几个类,可以使用“{}”
    • 比如:import scala.collection.mutable.{HashMap, HashSet}
  • 如果导入的多个包中有同名的类,可以将类的名字进行重命名
    • 比如:import scala.collection.mutable.{HashMap => JavaHashMap, HashSet}
  • 如果某个冲突的类根本不会用到,可以在导入时将其隐藏
    • 比如:import java.util.{HashMap => , }【引入所有,只忽略HashMap