① 包(package)
Why
包的三个主要作用是
-
区分类
: 区分相同名字的类
,防止命名冲突 -
管理类
:通过包来,管理类
. 控制访问
How
Java中的包
- java中的源文件保存在对应的包路径,本质上就是一个包对应一个文件夹.
- java中的字节码文件也保存在对应的包路径.
Scala中的包
- Scala中的包更加强大.不仅有如上三个特点,Scala中的包还能对类的功能进行拓展
Scala中包的命名规则
- 只能包含数字、字母、下划线、小圆点.,但不能用数字开头, 也不要使用关键字
命名规范
一般是小写字母+小圆点一般是, com.公司名.项目名.业务模块名
object TestTiger {
def main(args: Array[String]): Unit = {
val tiger1 = new com.sweetcs.bigdata.scala.day04.chapter07.packagedemo.scala.xh.Tiger
val tiger2 = new com.sweetcs.bigdata.scala.day04.chapter07.packagedemo.scala.xm.Tiger
println(tiger1 +"\t"+ tiger2)
}
}
Details
- Scala中
源文件
可以和包目录结构
不对应.但是编译后的字节码文件
必定和包目录结构
对应.(这是编译期特性)
graph TD
C(目录结构)
C --> |无需对应| D(源文件)
C --> |和目录结构对应| E(字节码文件)
- scala会自动引入的三个包.
java.lang.*
、scala
、Predef
- scala还有两种不同于java的两种打包方式, 主要介绍最后一种.(scala支持在一个文件中,同时创建多个包,以及trait,object)
第二种
package com.sweetcs
package scala
class Person{
val name = "lisi"
def play(message: String): Unit ={
}
}
代码说明
第三种(最常用,方便在一个文件中的不同包中创建class和trait)
/**
* @author sweetcs
*/
object AdvincePackageDemo {
def main(args: Array[String]): Unit = {
}
}
package com.sweetcs{
package scala{
class Person{
val name = "lisi"
def play(message: String): Unit ={
}
}
object Student {
}
}
}
编译后可以对应查看到如下内容
package com.sweetcs{
package scala{
class User {
}
class Person{
val name = "lisi"
def play(message: String): Unit ={
}
}
object Student {
}
}
package scala2 {
class User {
}
}
}
- 作用域1: Scala中的子包可以自己使用父包的内容,当Scala子包内容和父包冲突,默认使用最近原则.如果希望指定使用某个类,则带上包名即可.
package com.sweetcs{
package scala{
class User {
}
class Person{
val name = "lisi"
def play(message: String): Unit ={
}
}
object Student {
}
}
package scala2 {
class User {
}
object TestSubPackage {
def main(args: Array[String]): Unit = {
val user = new User // 不指定权限定类名使用最近原则
println(user)
val user2 = new com.sweetcs.scala.User // 指定某个类要用权限定类名
println(user2)
}
}
}
}
- 作用域2: 父包要访问子包的内容需要使用import关键字导入子包的内容
package com.sweetcs{
package scala{
class User {
def sayHello(): Unit = {
import com.sweetcs.scala.scala12.UserInScala12
val userInScala= new UserInScala12
userInScala.sayHello()
}
}
package scala12 {
class UserInScala12 {
def sayHello(): Unit = {
}
}
}
}
}
- Scala可以使用绝对路径引入包(当包名冲突时候可以使用这个方法,一般很少能用到)
②-包对象
Why
尽管我们可以在包中写class
、trait
、object
但是没法写函数
和方法
或者变量
.因为JVM的限制,无法这样做.于是scala提出了包对象技术就是为了解决这个缺陷,我们可以将函数
和方法
或者变量
写在包对象
中,相当于对包做了扩展,这样以后我们可以在包里调用这些写函数
和方法
或者变量
.
How
语法
package object 要扩展的包名 {
}
Demo
package com.sweetcs {
package object packageObject {
def sayHello(): Unit = {
println("hello packageobject")
}
}
package packageObject {
class User {
def callPackageObject(): Unit = {
sayHello()
}
}
object Test {
def main(args: Array[String]): Unit = {
val user = new User
user.callPackageObject()
}
}
}
}
What
包对象的运行原理,看反编译.如下图
包对象生成了两个对象package.class
和package$.class
在User类里,调用的是package$.MODULE$.sayHello()
.而这个MODULE$
是package$
类的一个静态实例对象.
如下核心的反编译源码
具体的调用关系
Details
- 每一个包有且仅能有一个包对象
- 每个一个包对象必须和其要扩展的包名字一样.
- 包对象底层会生成
package.class
和package$.class
.真正调用的时候调用的是package$.MODULE$的对应方法
,而这个MODULE$
是一个package$
类的静态实例 - 包对象和子包是一个平级关系,语法上写在同一个父包下.
③-Scala的访问修权限和包可见性
Why
几乎现代的所有编程语言都有访问控制权限,Scala也有,大部分和java类似,旦细节少也有不同.Scale中有private、protected、public、默认、四种访问权限修饰符
How
规则和语法
- 默认: 属性默认不写的话是private,且属性不能写public修饰.方法默认不写的话是public,方法也不能写public.
- private: 属性如果用private修饰,那么其只能在
本类
和其半生类
中被访问.方法亦是如此 - protected: Scala中的protected比java严格,声明为protected的,只能给有继承关系的类访问或者是本类.
- scalae中可以将一个private属性声明为对某些包可见,相当于对于这些包下的类来说private失效.
private[排除的包] var 成员变量名 :成员变量类型 = 变量值
Demo
package com.sweetcs.packagedemo.scala.advincepackage
/**
* @author sweetcs
*/
object ModifierDetailsDemo {
def main(args: Array[String]): Unit = {
val c = new User()
// public
println(c.name)
c.showInfo()
// protected
// c.address 错误 无继承关系无法访问
// c.protectedMethod 错误 无继承关系无法访问
// private
// c.privatedMethod 错误 私有方法无法访问
c.packagePrivateMethod()
println(c.phone)
}
}
class User {
var name : String = "jack"
private var sal : Double = 9999.9
protected var address :String = "beijing"
private[advincepackage] var phone :String = "110"
def showInfo(): Unit = {
println(" name " + name + " sal= " + sal)
}
protected def protectedMethod(): Unit = {
println("called protectedMethod")
}
private def privatedMethod(): Unit = {
println("called privateMethod")
}
private[advincepackage] def packagePrivateMethod(): Unit = {
println("called packagePrivateMethod")
}
}
object User{
def test(c : User): Unit = {
//这里体现出在伴生对象中,可以访问c.sal
println("test() name=" + c.name + " sal= " + c.sal)
}
}
Details
- 当
属性
访问权限为默认
时,底层对应的是private
,但是因为提供了xxx_$eq()[类似setter]/xxx()[类似getter]方法,因此我们可以通过这些方法访问到这个属性) - 当
方法
访问权限为默认时(不写),默认
为public
访问权限. - 在scala中没有public权限修饰,即
不能用public
显式的修饰属性
和方法
- protected为受保护权限, 在scala中protected比Java中更严格,只能子类访问,同包无法访问
- private为私有权限,只在类的内部和伴生对象中可用
④-Scale中包的引入
Why
包的引入技术对应打包技术,用来将在一个包内的类引入使用.
How
Scalae中的包引入分为以下几种
指定到一个类文件
指定到几个类文件
指定到父包,批量引入类文件
给引入的类文件的起别名(很少用,主要为了解决命名冲突,如果该类用)
隐藏掉引入的类,引入剩余类(很少用,主要为了解决命名冲突,如果该类不用)
/**
* @author sweetcs
*/
object ImportDetailDemo {
def main(args: Array[String]): Unit = {
}
}
class User {
// 1.指定到一个类文件
// import scala.beans.BeanProperty
// 2.指定到几个类文件
import scala.beans.{BeanProperty,BeanDescription}
@BeanProperty var name : String = ""
// 3.指定到父包,批量引入类文件
// import scala.beans._
// 4.给引入的类文件的起别名
import java.util.{HashMap => JavaHashMap}
var cache = new JavaHashMap()
// 5.隐藏掉引入的类,引入剩余类(很少用,主要为了解决命名冲突,如果该类不用)
import java.util.{ HashMap=>_, _} // 含义为 引入java.util包的所有类,但是忽略 HahsMap类.
var set = new HashSet()
}
class Dog {
import scala.beans.BeanProperty
@BeanProperty var name : String = ""
}