【大纲】
【正文】
1.包package
1.1.【结论】概念
0.包就是文件夹,用关键字package修饰,它可以区分重名类,相似功能的代码可以放一个包中,便于管理维护
1.编写源码时,scala的包名和源码所在的目录结构可以不一致,编译后,字节码文件会自动和包名路径一致。不过建议源码时最好保持一致
2.包名命名规范:
包名由 数字 大小写英文字母 _ $ 组成
多级包之间用.分隔
层级不限 一般2或3层
一般用公司域名反写命名 com.wsy.utils
1.2.语法
【结论】方式一 合并版 推荐
package xx.yy.zz
类/特质...
【结论】方式二 分解版
package xx.yy
package zz
类/特质...
【结论】方式三 串联式包语句
package xx.yy{
package zz{
类/特质...
}
}
1.3.【结论】作用域
0.子包可访问父包内容
1.上层访问下层内容时,需要导包import,或写全包名
2.如上下层有相同的类,则就近原则,想使用远的类,需用上层路径.类名
3.导包语法 后边会讲
示例
package com.wsy {
/**
* @author: WSY
* @description: 包 demo
* @creationDate: 2021/10/25 21:46
* @modifyDate: 2021/10/25 21:46
* @version: V1.0
*/
class Person {}
class Teacher {}
package scala{
class Person{}
class Student1{}
object demo{
def main(args: Array[String]): Unit = {
println(2)
// 子包可以直接访问父包中的内容
new Teacher
// 子父包有同名类时, 采用就近原则来访问
new Person
// 子父包有同名类, 且想访问父包类时, 写全路径即可
new com.wsy.Person
}
}
}
object Package {
def main(args: Array[String]): Unit = {
println("1")
// 方式一: 导包, 导包语句可以出现在Scala代码中的任意位置, 不一定是行首
import com.wsy.scala.Student1
new Student1
// 方式二: 全包名
new com.wsy.scala.Student1
// 因为当前包就是com.itheima, 所以上述代码可以简写成如下格式
new scala.Student1
}
}
}
1.4.【结论】包对象
0.由于JVM的限制,scala的包中,不能直接定义变量或方法,为了解决此问题,引入了包对象
1.定义包对象语法
package 父包A{
package 子包B{
}
// 子包B的包对象
package object 子包B{
}
}
# 注意:
0.包对象和包都要定义到父包中,这样才能使二者平级
1.包对象和包名必须一致
2.包对象一般用于对包的功能进行补充与增强
2.作用:
包对象的特性,主要是scala2.8为了兼容scala2.7.7旧版本而增加的
示例
package com.wsy{ // 父包
/**
* @author: WSY
* @description: 包对象 demo
* @creationDate: 2021/10/25 22:19
* @modifyDate: 2021/10/25 22:19
* @version: V1.0
*/
package scala{ // 子包
object PackageObject {
def main(args: Array[String]): Unit = {
// 访问当前包对象中的内容
println(scala.name) // 效果:tom
hello() // 效果:hello
}
}
}
package object scala{ // scala包的包对象 和scala包是平级关系
// 包对象中可定义成员
val name ="tom"
def hello() = println("hello")
}
}
1.5.【结论】包的可见性
访问权限修饰符private表示本类可用,private[com]来修饰成员,表示com包下所有类可用
示例
package com.wsy{ // 父包
/**
* @author: WSY
* @description: 包的可见性 demo
* @creationDate: 2021/10/25 22:33
* @modifyDate: 2021/10/25 22:33
* @version: V1.0
*/
class Employee{
private[wsy] val name = "tom"
val age = 16
private[com] def hello() = println("hello")
private def say() = println("say")
}
package scala{ // 子包
object PrivatePackage {
def main(args: Array[String]): Unit = {
val employee = new Employee
println(employee.name) // 效果:tom
println(employee.age) // 效果:16
employee.hello() // 效果:hello
// employee.say() // 效果:报错 无访问权限
}
}
}
}
1.6.【结论】包的引入
0.scala的导包语句不一定非要在行首,可以写到任何需要的地方,可缩小导包的作用范围,提高效率
1.scala默认引入的java.lang包、scala包部分内容、Predef包部分内容
2.导包语法
import 爷爷包.父包.子包.类名
3.导入某个包中所有内容:
import xx.yy._ # 下划线代表所有
4.仅导入某个包中的几个类或特质--包选取器
import xx.yy.zz.{类A, 特质B}
5.导入某个包下除了指定类的其他类
import java.util.{HashSet => _, HashMap => _, _}
6.为避免混淆,导入类时可重命名类名
import xx.yy.{原始类名A => 新类名AA, 原始类名B => 新类名BB}
示例
object ImportPackage {
def test01() = {
// 缩小import包的作用范围, 从而提高效率
import java.util.HashSet
val hs = new HashSet
// 导入包下的所有
import java.util._
val hm = new HashMap
val list = new ArrayList
}
def test02() = {
// 导入包下指定的类
import java.util.{ArrayList, HashSet}
val hs = new HashSet
val list = new ArrayList
}
def test03() ={
import scala.collection.mutable.HashSet
val hs = new HashSet()
// 导入类后重命名类
import java.util.{HashSet => JavaHashSet}
val jhs = new JavaHashSet
}
def test04() = {
// 导入包下除了指定类的其他类
import java.util.{HashSet => _, Hashtable => _, _}
val hm = new HashMap
// val hs = new HashSet // 效果:代码会报错
}
def main(args: Array[String]): Unit = {
test01
test02()
test03()
test04()
}
}
// 效果:都不报错
2.样例类
2.1.【结论】作用
scala中的样例类,是一种特殊类,编译器会自动帮样例类生成一些常用方法,样例类常用于保存数据,类似于java的POJO
2.2.【结论】语法
case class 样例类名(val/var 成员变量名: 数据类型 = 默认值, val/var 成员变量名: 数据类型 = 默认值){
}
# 注意:
0.主构造参数列表中,可以不写val/var,默认是val
1.默认值可以不给
示例
object CaseClass {
case class Person(name:String = "张三", var age:Int = 23){}
def main(args: Array[String]): Unit = {
val p = new Person()
p.age = 25
// p.name = "tom" // 直接报错 默认val不能修改
}
}
2.3.【结论】样例类中的默认实现
编译器会自动给样例类默认实现如下内容:
apply():
创建对象免new
toString():
println(样例类对象名),打印对象带各个属性值
equals():
p1 == p2 比较的是两个样例类对象的各个属性是否相等??
hashCode():
获取对象的哈希值,同一对象的哈希值一定相同,不同对象的哈希值一般不同
copy():
可快速创建一个属性值想用的对象,还可使用带名参数给指定的成员变量赋值
val p1 = new Person("张三", 23)
val p2 = p1.copy(age = 24)
println(p1) // 效果: 张三, 23
println(p2) // 效果: 张三, 24
unapply():
用作提取器,后边会讲
自动继承了Serializable特质
用作序列化和反序列化,后边会讲
示例
object CaseClass {
case class Person(var name:String, var age:Int){}
def main(args: Array[String]): Unit = {
// 样例类默认实现了apply方法 免new
val p1 = Person("张三", 23)
// 样例类重写了toString() 打印直接输出属性值
println(p1) // 效果:Person(张三,23)
// 样例类重写了toString() 可以获取到hash值
println(p1.hashCode())
// 样例类默认实现了copy方法
val p2 = p1.copy(age = 30)
println(p1.hashCode() == p2.hashCode()) // 效果:false
val p3 = p2.copy()
println(p2.hashCode() == p3.hashCode()) // 效果:true
}
}
3.样例对象
3.1.【结论】概念
单例样例类,也叫样例对象
3.2.【结论】语法
case object 单例样例类名
# 注意:
0.样例对象没有主构造器
3.3.【结论】作用
0.当作枚举值使用
trait Sex
case object Male extends Sex
case object Female extends Sex
1.作为没有任何参数的消息传递
后边会讲 在Akka并发编程处
示例
# 样例对象作为枚举值
object CaseObject {
trait Sex
case object Male extends Sex
case object Female extends Sex
case class Person(name:String, sex:Sex){}
def main(args: Array[String]): Unit = {
val tom = Person("tom", Male)
// Male如果用case修饰 这里打印出来的是Person(tom,Male)
// Male如果不用case修饰 这里打印出来的是Person(tom,com.wsy.CaseObject$Male$@56cbfb61)
println(tom)
}
}