Scala--第七天
一、内部类
定义:实现一个抽象类 或者 Trait 时 可以通过内部类的方式完成
1 abstract class Cmx { 2 def func: Unit 3 4 } 5 6 def main(args: Array[String]): Unit = { 7 var cmx = new Cmx { 8 override def func: Unit = { 9 println("我是内部类") 10 } 11 } 12 cmx.func 13 //我是内部类 14 }
二、特质 Trait
定义:类似于其它语言的接口
格式:trait 名称{
//抽象成员方法或属性
//普通成员方法或属性
}
注意:Trait中的抽象成员 必须全部实现 ,不然程序报错,如果实现不完整 只能称这个类为抽象类 需要加上abstract字段
1 trait cmx { 2 //抽象属性和普通属性 3 var name: String 4 var age = 10 5 6 //抽象方法和普通方法 7 def func(): Unit 8 9 def func1(): Unit = { 10 println("我是特质的普通方法") 11 } 12 } 13 14 class cmx01 extends cmx { 15 override var name = "cmx01" 16 17 override def func(): Unit = { 18 println("必须重写") 19 } 20 } 21 22 def main(args: Array[String]): Unit = { 23 var a = new cmx01 24 a.func() 25 println(a.name) 26 //必须重写 27 //cmx01 28 }
Trait与abstract的区别
1. abstract是单根继承体系,只能继承一个父类
Trait是多继承体系,可以被继承多个父类,使用关键字with
2. 在实战中,抽象类 表达的是 抽象的概念 名词
trait 表达的是 抽象的行为 动词
1 区别一 2 class Person 3 4 trait Cmx 5 6 trait Cmx01 7 8 class User extends Person with Cmx with Cmx01 { 9 print("---------") 10 } 11 12 def main(args: Array[String]): Unit = { 13 var a = new User 14 //主构造器的返回结果 15 //--------- 16 }
1 区别二 2 //打印日志是实际的动作,是个动词 3 trait Logger { 4 def log(msg: String) 5 } 6 7 class ConsoleLogger extends Logger { 8 override def log(msg: String): Unit = println(s"---控制台打印日志${msg}---") 9 } 10 11 class DBLogger extends Logger { 12 override def log(msg: String): Unit = println("----数据库存储日志----") 13 } 14 15 16 def main(args: Array[String]): Unit = { 17 var logger = new ConsoleLogger 18 logger.log("ok") 19 //---控制台打印日志ok--- 20 }
object 继承trait
1 trait cmx { 2 def func(): Unit 3 } 4 5 object A extends cmx { 6 override def func(): Unit = { 7 println("单例对象继承特质类") 8 } 9 } 10 11 def main(args: Array[String]): Unit = { 12 A.func() 13 //单例对象继承特质类 14 }
trait 可以和父类共存,但是注意父类一定要在前面,trait在后面,因为之后trait才能用with关键字
以下案例,将演示以上的案例,同时演示继承的构造顺序
1 class Person { 2 println("执行Person构造器") 3 } 4 5 trait Cmx { 6 println("执行Cmx构造器") 7 } 8 9 trait Cmx01 extends Cmx { 10 println("执行cmx01构造器") 11 } 12 13 trait Cmx02 extends Cmx { 14 println("执行cmx02构造器") 15 } 16 17 class User extends Person with Cmx01 with Cmx02 { 18 print("执行User构造器") 19 } 20 21 def main(args: Array[String]): Unit = { 22 var a = new User 23 //执行Person构造器 24 //执行Cmx构造器 25 //执行cmx01构造器 26 //执行cmx02构造器 27 //执行User构造器 28 }
对象混入trait
1 class Cmx() { 2 def func(): Unit = { 3 println("我是一个普通的类") 4 } 5 } 6 7 trait Cmx01 { 8 def func1(): Unit = { 9 println("我是一个特质的类") 10 } 11 } 12 13 def main(args: Array[String]): Unit = { 14 var a = new Cmx with Cmx01 15 a.func() 16 a.func1() 17 //我是一个普通的类 18 //我是一个特质的类 19 }
trait 也可以继承class
1 class Cmx() { 2 def func(): Unit = { 3 println("我是一个普通的类") 4 } 5 } 6 7 trait Cmx01 extends Cmx { 8 def func1(): Unit 9 } 10 11 class Test extends Cmx01 { 12 override def func1(): Unit = { 13 println("我是一个特质的实现") 14 } 15 } 16 17 def main(args: Array[String]): Unit = { 18 var a = new Test 19 a.func() 20 a.func1() 21 //我是一个普通的类 22 //我是一个特质的实现 23 }
三、样例类
定义:一种特殊的类,用来快速定义一个保存数据的类,类似与Java的实体,在后续spark,flink中及其重要
回顾已经学过的类:类,单例对象,半生对象,抽象类,Trait类,样例类
语法: case class 类名(属性名:属性类型...){...} ##这种写法,属性值的修饰符 是 val ,属性值不可变
case class 类名(var 属性名:属性类型...){...} ##这种写法 的属性值可以改变
注意:样例类使用来存储数据用的,所以没有方法
1 case class Cmx(var name: String) { 2 3 } 4 5 def main(args: Array[String]): Unit = { 6 var a = Cmx("cmx") 7 println(a.name) 8 //cmx 9 a.name = "cmx01" 10 println(a.name) 11 //cmx01 12 }
样例类的隐含方法
1.apply:快速创建对象,省去new关键字的书写
2.toString:将对象的内容,自动转换成字符串显示;而普通的类默认输出的是这个对象的地址(包.单利对象$类名@16进制hash码)
1 //普通类,改写默认方法 2 class Cmx(name: String) { 3 override def toString: String = { 4 return s"name= ${name}" 5 } 6 } 7 8 //普通类,为改写默认方法 9 class Cmx01(name: String) {} 10 11 def main(args: Array[String]): Unit = { 12 var a = new Cmx("cmx") 13 var b = new Cmx01("cmx01") 14 println(a.toString) 15 //name= cmx 16 println(b.toString) 17 //cmx_test.test2$Cmx01@d041cf #@符号后的是十六进制的哈希码 18 println(b.hashCode()) 19 //13648335 #这个方法返回的是十进制的哈希码 20 println(Integer.toHexString(b.hashCode())) 21 //d041cf #结果和前面的一样 22 }
3.equals方法:可以进行样例类,内容的比较
判断引用的方法eq()
判断内容的方法 equals(),==
1 case class Cmx(name: String) {} 2 3 def main(args: Array[String]): Unit = { 4 var a = Cmx("cmx") 5 var b = Cmx("cmx") 6 println(a.equals(b)) 7 //true 8 println(a.eq(b)) 9 //false 10 }
4.hascode方法:获取对象的哈希码,用于进行哈希操作,进行去重操作
注意:每个对象都有哈希码,但是哈希码不能代表对象的唯一标识
同一个对象的哈希码一定是相同的,不同对象的哈希码有可能是相同的
1 case class Cmx(name: String) { 2 3 } 4 5 def main(args: Array[String]): Unit = { 6 7 var a = Cmx("cmx") 8 var b = Cmx("cmx") 9 println(a.hashCode()) 10 println(b.hashCode()) 11 println(a.eq(b)) 12 //结果验证样例类的哈希码和内容保持一致,说明样例类修改了原来类的hashCode() 13 //-351660709 14 //-351660709 15 //false 16 }
5.copy方法:快速实现一个相同的对象(指的是数据内容相同)
1 case class Person(name: String, age: Int) 2 3 def main(args: Array[String]): Unit = { 4 var a = Person("cmx", 11) 5 var b = a.copy("cmx01") 6 print(b.toString) 7 //Person(cmx01,11) 8 }
四、样例对象
语法: case object 对象名字
定义枚举 : 一个类型 有有限的对象 (Sex Season ),在scala中通过 trait 和 样例对象 可以配合定义枚举类型
1 //性别 特质类 2 trait Sex 3 4 //样例对象 继承性别类 5 case object Male extends Sex 6 7 case object Female extends Sex 8 9 //样例类 参数性别的类型是Sex 10 case class Person(name: String, sex: Sex) 11 12 13 def main(args: Array[String]): Unit = { 14 var p = Person("suns", Male) 15 var p1 = Person("liwj", Female) 16 }
五、模式匹配
1.基本匹配
2.类型匹配
3.if条件判断匹配 守卫
4.样例类匹配
5.集合匹配
6.变量声明中的模式匹配
1 //基本匹配 2 var a = StdIn.readLine() 3 a match { 4 case "cmx" => println("cmx") 5 case "cmx01" => println("cmx01") 6 case _ => println("都不是") 7 } 8 //cmx
1 //类型匹配 2 var a: Any = 10 3 //模式匹配是可以有返回值的 4 //可以用一个参数代表a的值, 借以使用 5 var b = a match { 6 case x: String => s"String${x}" 7 case x: Int => s"Int${x.toString}" 8 } 9 //println(b) 10 //Int10
1 //if 条件判断 守卫 2 var a = 7 3 a match { 4 case _ if a >= 0 && a <= 3 => println("0---3") 5 case _ if a >= 4 && a <= 8 => println("4---8") 6 case _ => println("为匹配") 7 } 8 //4---8
1 //样例类匹配 2 case class Cmx(name: String) 3 case class Cmx01(age: Int) 4 var m: Any = Cmx("cmx") 5 var p: Any = Cmx01(20) 6 p match { 7 case Cmx(name) => println("cmx类") 8 case Cmx01(age) => println("cmx01类") 9 } 10 //cmx01类
1 //集合匹配 2 //三种形式 3 /* 4 List(1,_*):以1开头的列表 5 List(1):只有1一个元素的列表 6 List(1,x,y):以1 开头只有三个元素的列表 7 */ 8 var a = List(1, 2, 3, 4) 9 a match { 10 case List(1, _*) => println("该列表是1以开头的") 11 case List(1, x, y, z) => println("该列表共有4个元素") 12 case List(1) => println("该列表只有1 一个元素") 13 } 14 //该列表是1以开头的
1 var a = List(1, 2, 3, 4) 2 a match { 3 case 1 :: x :: y :: Nil => println("三个元素") 4 case 1 :: tail => println("以1开头的列表") // tail 代表尾部 可以用其他代替 5 case 1 :: n if n.length > 0 => println("以1开头的列表1") 6 case _ => println("其他") 7 } 8 //以1开头的列表
1 //变量声明过程中的模式匹配 2 //数组形式 3 var a = (1 to 10).toArray 4 var Array(_, x, y, _*) = a 5 println(x, y) 6 //(2,3) 7 8 //列表形式 9 var b = (1 to 10).toList 10 //tail也是个定位符,可以换成任意字符 11 var x :: y :: tail = b 12 println(x, y) 13 //(1,2)