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