文章目录
样例类
样例类是一种特殊类,它可以用来快速定义一个用于保存数据的类(类似于Java POJO类),在后续要学习并发编程和spark、flink这些框架也都会经常使用它。
定义样例类
语法格式
case class 样例类名([var/val] 成员变量名1:类型1, 成员变量名2:类型2, 成员变量名3:类型3)
- 如果要实现某个成员变量可以被修改,可以添加var
- 默认为val,可以省略
示例 | 定义一个样例类
需求
- 定义一个Person样例类,包含姓名和年龄成员变量
- 创建样例类的对象实例(“张三”、20),并打印它
参考代码
object _01CaseClassDemo {
case class Person(name:String, age:Int)
def main(args: Array[String]): Unit = {
val zhangsan = Person("张三", 20)
println(zhangsan)
}
}
示例 | 可变成员变量
需求
- 定义一个Person样例类,包含姓名和年龄成员变量
- 创建样例类的对象实例(“张三”、20)
- 修改张三的年龄为23岁,并打印
参考代码
object _02CaseClassDemo {
case class Person(var name:String, var age:Int)
def main(args: Array[String]): Unit = {
val zhangsan = Person("张三", 20)
zhangsan.age = 23
println(zhangsan)
}
}
# 样例类的方法
当我们定义一个样例类,编译器自动帮助我们实现了以下几个有用的方法:
- apply方法
- toString方法
- equals方法
- hashCode方法
- copy方法
apply方法
apply方法可以让我们快速地使用类名来创建对象。参考以下代码:
case class CasePerson(name:String, age:Int)
object CaseClassDemo {
def main(args: Array[String]): Unit = {
val lisi = CasePerson("李四", 21)
println(lisi.toString)
}
}
toString方法
toString返回样例类名称(成员变量1, 成员变量2, 成员变量3…),我们可以更方面查看样例类的成员
case class CasePerson(name:String, age:Int)
object CaseClassDemo {
def main(args: Array[String]): Unit = {
val lisi = CasePerson("李四", 21)
println(lisi.toString)
// 输出:CasePerson(李四,21)
}
}
equals方法
样例类自动实现了equals方法,可以直接使用==比较两个样例类是否相等,即所有的成员变量是否相等
示例
- 创建一个样例类Person,包含姓名、年龄
- 创建名字年龄分别为"李四", 21的两个对象
- 比较它们是否相等
val lisi1 = CasePerson("李四", 21)
val lisi2 = CasePerson("李四", 21)
println(lisi1 == lisi2)
// 输出:true
hashCode方法
样例类自动实现了hashCode方法,如果所有成员变量的值相同,则hash值相同,只要有一个不一样,则hash值不一样。
示例
- 创建名字年龄分别为"李四", 21的对象
- 再创建一个名字年龄分别为"李四", 22的对象
- 分别打印这两个对象的哈希值
val lisi1 = CasePerson("李四", 21)
val lisi2 = CasePerson("李四", 22)
println(lisi1.hashCode())
println(lisi2.hashCode())
copy方法
样例类实现了copy方法,可以快速创建一个相同的实例对象,可以使用带名参数指定给成员进行重新赋值
示例
- 创建名字年龄分别为"李四", 21的对象
- 通过copy拷贝,名字为"王五"的对象
val lisi1 = CasePerson("李四", 21)
val wangwu = lisi1.copy(name="王五")
println(wangwu)
样例对象
它主要用在两个地方:
- 定义枚举
- 作为没有任何参数的消息传递(后面Akka编程会讲到)
定义
使用case object可以创建样例对象。样例对象是单例的,而且它没有主构造器
语法格式
case object 样例对象名
示例 | 定义枚举
需求说明
- 定义一个性别Sex枚举,它只有两个实例(男性——Male、女性——Female)
- 创建一个Person类,它有两个成员(姓名、性别)
- 创建两个Person对象(“张三”、男性)、(“李四”、“女”)
参考代码
trait Sex /*定义一个性别特质*/
case object Male extends Sex // 定义一个样例对象并实现了Sex特质
case object Female extends Sex
case class Person(name:String, sex:Sex)
object CaseClassDemo {
def main(args: Array[String]): Unit = {
val zhangsan = Person("张三", Male)
println(zhangsan)
}
}
# 模式匹配
scala中有一个非常强大的模式匹配机制,可以应用在很多场景:
- switch语句
- 类型查询
- 使用模式匹配快速获取数据
简单模式匹配
在Java中,有switch关键字,可以简化if条件判断语句。在scala中,可以使用match表达式替代。
语法格式
变量 match {
case "常量1" => 表达式1
case "常量2" => 表达式2
case "常量3" => 表达式3
case _ => 表达式4 // 默认匹配
}
示例
需求说明
- 从控制台输入一个单词(使用StdIn.readLine方法)
- 判断该单词是否能够匹配以下单词,如果能匹配,返回一句话
- 打印这句话
单词 | 返回 |
---|---|
hadoop | 大数据分布式存储和计算框架 |
zookeeper | 大数据分布式协调服务框架 |
spark | 大数据分布式内存计算框架 |
未匹配 | 未匹配 |
参考代码
println("请输出一个词:")
// StdIn.readLine表示从控制台读取一行文本
val name = StdIn.readLine()
val result = name match {
case "hadoop" => "大数据分布式存储和计算框架"
case "zookeeper" => "大数据分布式协调服务框架"
case "spark" => "大数据分布式内存计算框架"
case _ => "未匹配"
}
println(result)
# 匹配类型
除了像Java中的switch匹配数据之外,match表达式还可以进行类型匹配。如果我们要根据不同的数据类型,来执行不同的逻辑,也可以使用match表达式来实现。
定义
语法格式
变量 match {
case 类型1变量名: 类型1 => 表达式1
case 类型2变量名: 类型2 => 表达式2
case 类型3变量名: 类型3 => 表达式3
...
case _ => 表达式4
}
示例
需求说明
- 定义一个变量为Any类型,然后分别给其赋值为"hadoop"、1、1.0
- 定义模式匹配,然后分别打印类型的名称
参考代码
val a:Any = "hadoop"
val result = a match {
case _:String => "String"
case _:Int => "Int"
case _:Double => "Double"
}
println(result)
[!NOTE]
如果case表达式中无需使用到匹配到的变量,可以使用下划线代代替
守卫
在Java中,只能简单地添加多个case标签,例如:要匹配0-7,就需要写出来8个case语句。例如:
int a = 0;
switch(a) {
case 0: a += 1;
case 1: a += 1;
case 2: a += 1;
case 3: a += 1;
case 4: a += 2;
case 5: a += 2;
case 6: a += 2;
case 7: a += 2;
default: a = 0;
}
在scala中,可以使用守卫来简化上述代码——也就是在case语句中添加if条件判断。
示例
需求说明
- 从控制台读入一个数字a(使用StdIn.readInt)
- 如果 a >= 0 而且 a <= 3,打印[0-3]
- 如果 a >= 4 而且 a <= 8,打印[3,8]
- 否则,打印未匹配
参考代码
val a = StdIn.readInt()
a match {
case _ if a >= 0 && a <= 3 => println("[0-3]")
case _ if a >= 4 && a <= 8 => println("[3-8]")
case _ => println("未匹配")
}
# 匹配样例类
scala可以使用模式匹配来匹配样例类,从而可以快速获取样例类中的成员数据。后续,我们在开发Akka案例时,还会用到。
示例
需求说明
- 创建两个样例类Customer、Order
- Customer包含姓名、年龄字段
- Order包含id字段
- 分别定义两个案例类的对象,并指定为Any类型
- 使用模式匹配这两个对象,并分别打印它们的成员变量值
参考代码
// 1. 创建两个样例类
case class Person(name:String, age:Int)
case class Order(id:String)
def main(args: Array[String]): Unit = {
// 2. 创建样例类对象,并赋值为Any类型
val zhangsan:Any = Person("张三", 20)
val order1:Any = Order("001")
// 3. 使用match...case表达式来进行模式匹配
// 获取样例类中成员变量
order1 match {
case Person(name, age) => println(s"姓名:${name} 年龄:${age}")
case Order(id1) => println(s"ID为:${id1}")
case _ => println("未匹配")
}
}
匹配集合
scala中的模式匹配,还能用来匹配集合。
匹配数组
示例说明
-
依次修改代码定义以下三个数组
Array(1,x,y) // 以1开头,后续的两个元素不固定 Array(0) // 只匹配一个0元素的元素 Array(0, ...) // 可以任意数量,但是以0开头
-
使用模式匹配上述数组
参考代码
val arr = Array(1, 3, 5)
arr match {
case Array(1, x, y) => println(x + " " + y)
case Array(0) => println("only 0")
case Array(0, _*) => println("0 ...")
case _ => println("something else")
}
匹配列表
示例说明
-
依次修改代码定义以下三个列表
List(0) // 只保存0一个元素的列表 List(0,...) // 以0开头的列表,数量不固定 List(x,y) // 只包含两个元素的列表
-
使用模式匹配上述列表
参考代码
val list = List(0, 1, 2)
list match {
case 0 :: Nil => println("只有0的列表")
case 0 :: tail => println("0开头的列表")
case x :: y :: Nil => println(s"只有另两个元素${x}, ${y}的列表")
case _ => println("未匹配")
}
匹配元组
示例说明
-
依次修改代码定义以下两个元组
(1, x, y) // 以1开头的、一共三个元素的元组 (x, y, 5) // 一共有三个元素,最后一个元素为5的元组
-
使用模式匹配上述元素
参考代码
val tuple = (2, 2, 5)
tuple match {
case (1, x, y) => println(s"三个元素,1开头的元组:1, ${x}, ${y}")
case (x, y, 5) => println(s"三个元素,5结尾的元组:${x}, ${y}, 5")
case _ => println("未匹配")
}
# 变量声明中的模式匹配
在定义变量的时候,可以使用模式匹配快速获取数据
示例 | 获取数组中的元素
需求说明
- 生成包含0-10数字的数组,使用模式匹配分别获取第二个、第三个、第四个元素
参考代码
val array = (1 to 10).toArray
val Array(_, x, y, z, _*) = array
println(x, y, z)
示例 | 获取List中的数据
需求说明
- 生成包含0-10数字的列表,使用模式匹配分别获取第一个、第二个元素
参考代码
val list = (1 to 10).toList
val x :: y :: tail = list
println(x, y)