大数据基础-scala简介,安装配置,基础语法,类和对象(单例对象,伴生对象,isinstance,asInstance,getClass,classOf,抽象类,匿名内部类,特质)

环境统一:
jdk:1.8
安装scala SDK(针对scala语言的编译器):2.11.8
安装IDEA插件:2019.1.7

目录标题

scala简介

啥是scala:说白了就是运行在JVM上的python,可以跟java无缝衔接

scala安装配置

参照此链接进行安装配置

scala基础语法格式

1.开启scala解释器,并执行hello world

使用scala解释器可以方便我们做一些小的测试,练习
键盘windows按键+r
输入scala回车
在这里插入图片描述

println("hello,world")

在这里插入图片描述
推出scala解释器

:quit

2.变量

(1)语法格式

在scala中,使用val或者var来定义变量

var/val 变量标识:变量类型(可以省略不写) = 初始值
  • var定义是可重新赋值的变量

  • val定义的是不可重新赋值的变量

  • 示例演示:

val name:String = "tom"
var name:String = "tom"
name = "jim" //重新赋值

(2)惰性赋值

当有一些变量的数据比较大时,但是不需要要马上加载到JVM内存,可以使用惰性赋值来提高效率
使用场景:当我们在大数据开发时候会编写非常赋值的sql宇哥,这些语句可能成百上前行,如果把这些sql直接加载到JVM当中会产生很大的内存开销,我们这个时候就可以使用scala的惰性赋值

  • 语法格式
lazy val/var 变量名 = 表达式

4.字符串

(1)插值表达式

直接在字符串内引用引用内容写在{ }中,直接避免使用+号进行拼接

  • 语法
val/var 变量名 = s"${变量/表达式}字符串"

-示例

val name = "zhangsan"
val age = 30
val sex = "male"
//使用插值表达式
val info = s"name=${name},age=${age},sex=${sex}"

(2)使用三引号

使用场景:面对一大段的文本数据需要保存,可以使用三引号

5.条件表达式

(1)有返回值的if

在scala中,if条件表达式是有返回值的

val sex ="male"
val result = if(sex="male") 1 else 0

(2)块表达式

  • 在scala中使用{ }表示一个块表达式
  • 和if表达式一样,块表达式也是有值得
  • 值就是最后一个表达式的值
    在这里插入图片描述

6.循环

(1)for表达式

  • 语法
for(i<- 表达式/数字/集合>){
	//表达式
}
  • 示例演示
    使用for表达式打印1-10的数字
for(i <- 1 to 10) println(i)

(2)嵌套循环

使用for表达式,打印以下字符

*****
*****
*****
*****
for(i <- 1 to 3;j<-1 to 5) {print("*");if(j==5) println("")}

(3)在for表达式中添加判读语句

for (i <- 表达式/集合/数字 if 表达式){
	//表达式
}
  • 示例演示
    使用for表达式打印1-10直接能够整除3的数字
for(i <- 1 to 10 if i%3 == 0) println(i)

(4)for推导式

//for推导式:for表达式中以yield开始,for表达式会构建出一个集合
val v =for(i <- 1 to 10) yield i*10

(5)while循环

var i =1
while(i <=10){
println(i)
i = i+1
}

(6)实现break

用法

  • 导入Breaks包import scala.util.control.Breaks._

  • 使用breakable将for表达式包起来

  • for表达式中需要退出循环的地方,添加break()方法调用

  • 示例演示
    使用for表达式打印1-100的数字,如果实到达50,退出for表达式

//导入scala.util.control包下的Break
improt scala.util.control.Breaks._
breakable{
	for(i<- 1 to 100)
	if(i>=50) break()
	else println(i)


}

(7)continue跳过

实现break是用breakable{}将整个for表达式包起来,而实现continue是用breakable{}将for表达式的循环体包含起来就可以了
遇见能整除10的就不打印

import scala.util.control.Breaks._
for(i <- 1 to 100){
	breakable{
		if(i%10 == 0) break()
		else println(i)
}

}

(8)foreach

打印1到10的数组

(1 to 10).foreach(println(_))

7.方法

(1)方法的定义

方法有两部分组成=等号左边是参数,=等号右边是方法体

def format(date:Date) = simpleDateFormat.format(date)

(2)方法的调用

  1. 后缀调用法
对象名.方法名(参数)
Math.abs(-1)
  1. 中缀调用法
对象名 方法名 参数(如果参数有多个可以使用括号括起来)
Math abs -1
  1. 花括号调用
Math.abs{
	//表达式1
	//表达式2
}

注意:只能是方法仅有一个参数时,才可以使用花括号调用法

  1. 无括号调用法
    如果方法没有参数,可以省略方法名后面的括号
def m3()=print("hello")
m3()

8.函数

(1)定义函数

语法

val 函数变量名 = (参数名:参数类型,参数名:参数类型...)=>函数体

函数是一个变量
函数类似方法也有输入参数和返回值
无需指定返回值类型

  • 示例演示
val add = (x:int,y:int) => x + y
add(1,2)

(2)方法和函数的区别

  • 函数用的=> 而方法是=
  • 方法是一个类下面的一个功能,例如:Math类的abs求绝对值方法
  • 函数是一个变量,他可以在赋值给另一个变量
  • 函数对象有apply,curried,toString,tuoled这些方法.而方法则没有

(3)方法转化为函数

  • 有时候需要将方法转换为函数,作为变量传递,就需要将方法转换为函数
  • 使用 _ 即可将方法转换为函数
  • 示例演示
def add(x:Int,y:Int) = x+y
val a = add _

9.数组

(1)定长数组

  • 数组长度步允许改变
  • 数组的元素是可以改变的
//通过指定长度定义数组
val/var 变量名 = new Array[元素类型](数组长度)

//用元素直接初始化数组
val/var 变量名 = Array(元素1,元素2,元素3...)
  • 示例演示
val a = new Array[Int](100)
a(0) = 100
println(a(0))

(2)变长数组

(3)遍历数组

  • 使用for表达式直接遍历数组中的元素
val a = new Array[Int](1,2,3,4,5)
for(i <- a) println(i)
  • 使用索引下标遍历数组中的元素
val a = new Array[Int](1,2,3,4,5)
for(i <- 0 to a.length-1) println(a(i))

数组常用算法

  • 求和sum方法
val a = Array(1,2,3,4)
a.sum
  • 求最大值max方法
val a = Array(1,2,3,4)
a.max
  • 求最小值min方法
val a = Array(1,2,3,4)
a.min
  • 排序sorted升序方法,而reverse方法,可以将数组进行反转,从而实现降序排序
val a = Array(1,2,3,4,10)
//升序
a.sorted
//降序
a.sorted.reverse

10.元组

元组可以用来包含一组不同类型的值

(1)定义元组

  • 使用括号定义
val/var 元组 = (元素1,元素2,元素3...)
val a = (1,"zhangsan",20,"beijing")
  • 使用箭头定义,元组内仅仅只能有两个元素
val/var 元组 = 元素1->元素2
val a = "zhangsan" -> 30

(2)访问元组

使用_1,_2,_3来访问元组中的元素

val a = "zhangsan" -> 20
a._1

11.列表

(1)不可变列表

不可变列表就是列表元素,长度都是不可改变的

var/val 变量名 = List(元素1,元素2,元素3...)

使用Nil创建

val/var 变量名 = Nil

使用::方法创建一个不可变列表

val/var 变量名 = 元素1::元素2::Nil

(2)可变列表

可变列表就是列表的元素和列表的长度是可以改变的说白了就是:列表可以实现增删改的功能

  • 注意事项:
    可变集合都在mutable包中(需要手动导入)
    不可变集合都在immutable包中(默认导入的)
  • 方式1:
import scala.collection.mutable.ListBuffer
val/var 变量名 = ListBuffer[Int]()
  • 方式2:
import scala.collection.mutable.ListBuffer
var/val 变量名 = ListBuffer(元素1,元素2,元素3...)

(3)可变列表操作

  • 获取元素(使用括号索引值访问)
  • 添加元素(+=)
  • 追加元素(++=)
  • 更改元素(使用括号获取元素,然后进行赋值)
  • 删除元素(-=)
  • 转化成不可变列表(toList)
  • 转化为Array(toArray)

(4)列表常用操作

  • 判断是否为空(isEmpty)
  • 拼接两个列表(++)
  • 获取列表的首个元素(head)和剩余部分(tail)
  • 反转列表(reverse)
  • 获取前缀(take(前几个元素)),获取后缀(drop(后几个元素))
  • 扁平化(flaten)
    扁平化也也叫压平操作,是指一个列表内还嵌套这多个列表,我们对其进行扁平化操作后,内嵌的多个列表就会被去除,但是内部的元素依旧会被保留下来
val a = List(List(1,2),List(3,4),List(5,6))
a.flatten
  • 拉链(zip)和拉开(unzip)
    拉链:使用zip将两个列表,组合成为一个元素为元组的列表
    在这里插入图片描述
    拉开:将一个包含元组的列表,解开成包含两个列表的元组
    在这里插入图片描述刚好和拉链操作是相反的
  • 转换成字符串(toString)
  • 生成字符串(mkString)
    mkString方法可以将元素以指定的分隔符进行拼接
val a = List(1,2,3,4)

a.mkString(":")
  • 并集(union)
    使用union是不去重的
    使用distinct操作,去除重复的元素
  • 交集(intersect)
  • 差集(diff)
    例如a1.diff(a2),表示获取a1在a2中不存在的元素

12.集

(1)不可变集

(2)可变集

与不可变集创建方法一致,但是需要手动导入一个不可变集类

import scala.collection.mutable.Set
val a = Set(1,2,3,4)
a+=5
a-=1

13.映射

(1)不可变map

不可变map指的是元素的k,v都是不可以被改变的,也不可以新添加,删除k,v对

  • 方式1:
val/var map = Map(->值,->值,..)
  • 方式2:
val/var map Map((,),(,),...)

可以通过k值来获取v值

(2)可变map

可变map是指其中元素的k,v键值对都是可以修改的

import scala.collection.mutable.Map
val map = Map("zhangsan"->30,"lisi"->40)
map("zhangsan")=20

14.迭代器

scala针对每一类集合都提供了一个迭代器用来访问集合
使用迭代器遍历集合

  • 使用iterator方法可以从集合获取一个迭代器
  • 迭代器的两个基本操作
    1. hasNext:查询容器中是否有下一个元素
    2. next:返回迭代器的下一个元素
val a = List(1,2,3,4,5)
val ite = a.iterator
while(ite.hasNext)
println(ite.next)
val a = List(1,2,3,4,5)
for(i <- a) println(i)

15.函数式编程

  • 基础符号讲解
    =>b箭头右边b是方法体,方法体的结果就是返回值
    a=>箭头左边a是传入参数
    参数在函数体中出现了一次,函数体中没有嵌套调用的,就可以用_来替代函数参数
    k -> v 单箭头的kv对映射

(1)遍历(foreach)

val a = List(1,2,3,4)
a.foreach(x=>println(x))

(2)映射(map)

map方法接收一个函数,将这个函数用于带每一个元素,返回一个新的列表

val lst = List(1,2,3,4)
lst.map(lst=>lst+1)
val a = List(1,2,3,4)
a.map(_+1)

(3)映射扁平化(flatmap)

切割字符串将一个文件列表转换成为一个一个的单词的列表
flatmap是先进行map,列表分为多个字符串,得到多个这种数据[“hadoop spark hadoop”],在进行flat对字符串内数据在进行拆解按照指定分隔符拆分,我们就得到最后的[“hadoop”,“spark”,“hadoop”]
[hadoop,sqoop,hadoop]

LineList = ["hadoop spark hadoop"]
lineList.flatMap(_.split(" "))

返回的是
[“hadoop”,“spark”,“hadoop”]

(4)过滤(filter)

过滤符合一定条件的元素

val lst = List(1,2,3,4,5,6)
lst.filter(lst => lst % 2)
val lst = List(1,2,3,4,5,6)
lst.filter(_ % 2)

(5)是否存在(exists)

在这里插入代码片

(6)排序(sorted,sortBy,sortWith)

1.默认升序排序sorted
List(3,1,2,9,7).sorted
2.指定字段排序sortBy
val lst = List("01 hadoop","02 flume","03 hive","04 spark")
lst.sortBy(_.split(" ")(1))
3.自定义排序

根据一个函数来进行自定义排序

val a = List(2,3,1,6,4,5)
a.sortWith((x,y) => if(x<y)true else false)

(7)分组(groupBy)

val a = List("张三"->"男","李四"->"女","王五"->"男")  //列表内放置的一对对元组
val groupMap = a.groupBy(x=>x._2)  //元组的访问使用_1,_2...来访问,这里的下滑线_不是代替参数的作用
groupMap.map(x=>x._1 -> x.2.size)

(8)聚合计算(reduce)

可以将一个列表中的数据合并为一个
x是上一次两个数相加的结果值,y是下一个元素的值

val a = List(1,2,3,4,5,6,7,8,9,10)
a.reduce((x,y)=>x+y)
val a = List(1,2,3,4,5,6,7,8,9,10)
a.reduce(_+_)

(9)折叠(fold)

val a = List(1,2,3,4,5,6,7,8,9,10)
a.fold(0)(_+_) //第一个括号是指定聚合前的初始值

scala类和对象

1.类和对象

(1)创建类和对象

  • 使用class来定义一个类
  • 使用new来创建对象
    在这里插入图片描述
    创建一个单例对象,如果要有main方法就必须创建一个单例对象,此对象好比是程序的入口
    在这里插入图片描述
object ClassObject {
  class Person{ //创建一个类

  }

  def main(args: Array[String]): Unit = {
    val person = new Person() //创建对象,idea快捷键是new Person().var
    println(person)
  }

(2)简写方式

  • 如果类是空的,没有任何成员可以省略{ }
  • 如果构造器的参数为空,可以省略()
object ClassObject {
  class Person

  def main(args: Array[String]): Unit = {
    val person = new Person
    println(person)
  }
}

(3)定义和访问成员变量

  • 在类中使用var/val来定义成员变量
  • 对象直接使用成员变量来访问成员变量
在这里插入代码片

(4)使用下划线来初始化成员变量

object ClassObject {
  class Person {
    //定义成员变量
    var name: String = _
    var age: Int = _
  }
  def main(args: Array[String]): Unit = {
    val person = new Person
    person.name = "张三"
    person.age = 30
    println(person.name,person.age)
  }
}


(5)定义成员方法

类可以有自己的行为,scala中也可以通过定义成员方法来定义类的行为

object ClassObject {
  class Customer {
    //定义成员变量
    var name: String = _
    var sex: String = _
    //定义成员方法
    def printHello(msg:String): Unit =println(msg)
  }
  def main(args: Array[String]): Unit = {
    val customer = new Customer
    customer.printHello("你好")
  }
}

(6)访问修饰符

通过访问修饰符private,来控制成员变量和成员方法是否可以被访问

object ClassObject {
  class Person{
    private var name = ""
    private var age = 0
    
    def getName() = this.name
    def getAge() = this.age
    def setName(name:String) = this.name = name
    def setAge(age:Int) = this.age = age
    //获取姓名和年龄返回的是一个元组
    private def getNameAndAge() = (this.name,this.age)
  }
  def main(args: Array[String]): Unit = {
    val person = new Person
    person.setName("张三")
    person.setAge(30)
    
  }
}

(7)类的构造器(java的无参构造有参构造)

当创建类对象的时候,会自动调用类的构造器,主构造器的参数会自动成为成员变量

1.主构造器
object ClassObject {
  class Person(var name:String="",var age:Int=0){
    println("调用主构造器")

  }
  def main(args: Array[String]): Unit = {
    val zhangsan = new Person("张三",20)
    println(zhangsan.name)
    println(zhangsan.age)

  }
}

(2)辅助构造器

  • 辅助构造器的使用场景:可以实现主构造器,能允许多种方式来创建对象
  • 定义辅助构造器与定义方法一样,也使用def关键字来定义
  • 这个方法的名字为this
  • 辅助构造器是定义在主构造器内容部的
def this(参数名:类型,..){
	//第一行需要调用主构造器,或者其他构造器
	//构造器代码
}

通过辅助构造器实现创建对象时数组传递构造参数

object ClassObject {
  class Customer(var name:String="",var addr:String=""){
    def this(data:Array[String]){
      this(data(0),data(1)) //this是主构造器自己,传入数组的0号位,和1号位参赛
    }

  }

  def main(args: Array[String]): Unit = {
    val customer = new Customer(Array("张三","北京"))
    println(customer.name)
    println(customer.addr)
    
  }
}

2.单例对象–object

(1)单例对象

单例对象在java中就是static静态成员变量.就是把所修饰的内容提高到类全局中,表示整个类共享此内容
例如:学生类有不同的学生,小明,小王,小李,但是都是同一所学校,北京蓝天幼稚园,我们通过static 蓝天幼稚园.可以把此变量提高到类全局,凡是本类的都会共享此数据.

  • 示例1
object ClassObject {
  //创建单例对象
  object Dog{
    //定义了一个单例对象的成员.类似java的static
    val LEG_NUM = 4
  }
  //访问单例对象的成员变量
  def main(args: Array[String]): Unit = {
    Dog.LEG_NUM

  }
}
  • 示例2
object ClassObject {
  //创建一个单例对象,定义成员方法
  object PrintUtil{
    def printSpliter() = {  
      println("-" * 15)
    }
  }
  //访问单例对象的成员变量
  def main(args: Array[String]): Unit = {
    PrintUtil.printSpliter()

  }
}

(2)工具类案例

需求

  • 编写一个DateUtil工具类专门用来格式化日期时间
  • 定义一个方法,用于将日期转化为年月日字符串,例如:2030-10-05
import java.text.SimpleDateFormat
import java.util.Date

object ClassObject {
  object DateUtil {
  //scala可以直接的调用java的相关包
    private val simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd")

    //定义一个用于日期格式化的方法
    def format(date:Date)= simpleDateFormat.format(date)
    
  }
  //访问单例对象的成员变量
  def main(args: Array[String]): Unit = {
    val now = new Date()
    println(DateUtil.format(now))

  }
}

(3)main方法

如果要运行一个程序,必须要有一个main方法.,而这个main方法必须放在一个单例对象中

object ClassObject {
  def main(args: Array[String]): Unit = {
    println("hello scala")

  }
实现AppTrait来定义入口

创建一个object,继承自App,然后将需要编写在main方法中的代码,写在object的构造方法体内

object 单例对象名 extends App {
	//方法体
}

object ClassObject extends App{
  println("hello Scala")
  
}

3.伴生对象

使用场景是:
1. 经常会有一些类,同时又实例成员又有静态成员,我们要实现这样的效果,就需要使用伴生对象来实现
2. 还可以使用伴生对象来实现快速创建对象
3. 弥补类中不能定义 static 属性(单例对象)的缺陷。

(1)定义伴生对象

  1. 定义一个 class 并在这里面实现所有的实例成员。
  2. 添加一个 object ,这个 object 要与上面的 class 同名,然后在这里面实现所有的静态成员。

注意:

  • 伴生对象object+名称,必须要和伴生类class+名称,名称一致
  • 伴生对象和伴生类在同一个scala源文件中
  • 伴生对象和伴生类可以互相访问private属性
object ClassObject{
  //1.创建一个伴生类
  class CustomerService{
    def save()= println(CustomerService.SERVICE_NAME)
  }
  //2.创建一个伴生对象
  object CustomerService{
    private val SERVICE_NAME = "保存客户"
  }
  //3.创建对象,调用方法
  def main(args: Array[String]): Unit = {
    val service = new CustomerService()
    service.save()
  }
}

(2)private[this]访问权限

如果某个成员的权限设置为private[this],表示只能在当前类中访问.伴生对象也不可以访问

object ClassObject{
  class Persion(private[this] var name:String)
  
  //创建Person类伴生对象
  object Persion{
    def printPersion(p:Persion): Unit ={
      println(p.name) //报错
    }
  }
 }

4.继承

使用场景:通过集成来减少重复的代码

object ClassObject{
  class Person{
    var name:String = _
    def getName() = this.name
  }
  //2.创建一个Student类,继承Person类
  class Student extends Person
  //3.创建Student对象访问其成员变量
  private val student = new Student
  student.name
}

5.override,super

使用override重写父类成员,可以使用super来引用父类

  • 子类要覆盖重写父类的一个方法,必须要使用override关键字
  • 使用override来重写一个vai字段
  • 使用super关键字来访问父类的成员方法
  • 覆盖重写成员字段必须是不可变val类型
object ClassObject{
  class Person{
    val name = ""
    def getName() = this.name
  }
  class Student extends Person {
    override val name = "张三"
    override def getName(): String = "hello"+name
  }

  def main(args: Array[String]): Unit = {
    val student = new Student
    println(student.getName())
  }
}

6.isInstanceOf/asInstanceOf类型判断和类型转换

  • isInstanceOf判断对象是否为指定类对象或其子类
  • asinstanceOf将对象转换为指定类型,等同于一个强转
  • 用法
//判断对象是否为指定类型
var trueorFalse = 对象.inInstanceOf[类型]
//将对象转换为指定类型
val 变量 = 对象.asInstanceOf[类型]

object ClassObject{
  class Person
  class Student extends Person

  def main(args: Array[String]): Unit = {
    val student = new Student
    if(student.isInstanceOf[Student]){  //这个中括号[数据类型]不可省略
      println(student.asInstanceOf[Student]) //这个中括号[数据类型]不可省略
    }
  }
}

7.getClass和classOf

使用场景:使用isInstance只能去判断一个对象是否为指定类对象或其子类(不精准,父类子类他都会说是true),而不能精准的获得说这个对象的具体类是子类还是父类
当使用getClass他会精准的区分其类的类型是子类类型,还是父类类型,还是什么其他类型.不会因为子父类一继承,而把它们归为一谈

  • p.getClass可以精准的获取对象的类型
  • classOf[x]可以精准的获取类型
  • 使用==操作符可以直接比较类型
object ClassObject{
  class Person
  class Student extends Person
  //创建对象,判断对象的类型(isInstanceOf)
  def main(args: Array[String]): Unit = {
    val student:Person = new Student

    if(student.isInstanceOf[Person]){
      println("isinstance判断:是Person类型")
    }
    else {
      println("isinstance判断:不是Person类型")
    }
    //使用getClass获取对象类型
    //使用classOf获取类的类型
    if (student.getClass == classOf[Person]){
      println("getClass判断是Person类型")
    }
    println("getClass判断不是Person类型")
    if (student.getClass == classOf[Student]){
      println("getClass判断是student类型")
    }
    else {
      println("不是student类型")
    }

  }
}

8.抽象类

  • 抽象方法:方法没有方法体
  • 抽象字段:变量没有初始值
  • 抽象类与java定义抽象类一致.在class关键字前面加上abstract关键字
package com.yuge.scala.experence

object ClassObject{
  abstract class Shape{
    //定义抽象方法,返回值是Double
    def area():Double

  }
  class Square(var edge:Double) extends Shape{
    //计算正方形面积
    override def area(): Double = edge*edge
  }
  //计算长方形面积
  class Rectangle(var length:Double,var width:Double) extends Shape{
    override def area(): Double = length * width
  }
  //计算圆形面积
  class Circle(var r:Double) extends Shape{
    override def area(): Double = Math.PI * r * r
  }

  //创建实现类对象,求面积
  def main(args: Array[String]): Unit = {
    //求长方形面积
    val square = new Square(2.0)
    println(square.area())

  }
}

9.匿名内部类

scala匿名内部类与java一致:没有名称的子类
使用场景:直接在程序中创建,实现抽象类,其主要作用就是可以简单便捷的实现抽象类,减少在创建一个单独类实现抽象方法,在调用抽象方法的过程

object ClassObject{
  //定义一个抽象方法
  abstract class Person{
    def sayHello()
  }
  def main(args: Array[String]): Unit = {
    new Person {
      override def sayHello(): Unit = println("hello")
    }.sayHello()
  }
}

10.特质(java的接口)

  • 他可以将方法和字段定义封装起来,然后添加到类中
  • 一个类只能继承一个父类,而一个类可以添加任意数量的特质
  • 定义使用的关键字是trait

(1)定义特质

  1. 定义
trait 名称{
	//抽象字段
	//抽象方法
}
  1. 特质的继承
classextends 特质1 with 特质2{
	//字段实现
	//方法实现
}
  • 示例1
object ClassObject{
  //1.创建一个特质
  trait Logger{
    //可以在特质中定义抽象方法
    def log(msg:String)
  }
  //2.创建一个实现类,继承特质
  class ConsoleLogger extends Logger{
    override def log(msg: String): Unit = println("控制台消息"+msg)
  }
  //3.创建实现类的对象,调用实现方法
  def main(args: Array[String]): Unit = {
    val logger = new ConsoleLogger
    logger.log("NullPointer Exception")
  }
}

  • 示例2:多继承特质
object ClassObject{
  //1.创建两个个特质,两个抽象方法
  trait MessageSender{
    def send(msg:String)
  }
  trait MessageReceive{
    def receive():String
  }
  //2.创建一个实现类,继承特质
  class MessageWorker extends MessageReceive with MessageSender{
    override def receive(): String = "接收成功"

    override def send(msg:String): Unit = println("控制台发送"+msg)
  }
  //3.创建实现类的对象,调用实现方法
  def main(args: Array[String]): Unit = {
    val worker = new MessageWorker
    worker send("收到了么?")
    println(worker.receive())
  }
}

  • 示例3:object单例对象也可以继承特质
package com.yuge.scala.experence

object ClassObject{
  //1.创建一个特质,定义抽象方法
  trait Logger{
    def Log(msg:String)
  }
  //2.定义单例对象,继承特质
  object ConsoleLogger extends Logger{
    override def Log(msg:String): Unit = println("控制台消息"+msg)
  }
  //3调用单例对象的实现方法
  def main(args: Array[String]): Unit = {
    ConsoleLogger.Log("hello Scala")
  }
}

(2)特质内部定义具体方法

使用场景:主要是解决出现大量的重复代码,我们可以把它们封装在特质中,在使用时直接继承特质然后后调用,避免出现反复编写重复代码

object ClassObject{
  //1.创建一个特质,定义具体实现方法
  trait Logger{
    def Log(msg:String) = println(msg)
  }
  //2.定义一个类,继承特质
  class UserService extends Logger{
    def add() = Log("添加用户")
  }

  //3调用单例对象的实现方法
  def main(args: Array[String]): Unit = {
    val service = new UserService
    service.add()
  }
}

(3)使用trait实现模板模式

需要分析:

  • 编写一个日志输出工具,分别有info,warn,error三个级别的日志输出
  • 日志输出方式要求设计为可扩展的:可以输出到数据库,控制台,文件
object ClassObject{
  //1.创建一个特质,具体方法会调用抽象方法,输出不同级别日志
  trait Logger{
    def Log(msg:String)
    //具体方法->去实现抽象方法
    def info(msg:String) = Log("信息:"+msg)
    def warn(msg:String) = Log("警告:"+msg)
    def error(msg:String) = Log("错误:"+msg)
  }
  //2.定义一个实现类,继承特质
  class ConsoleLogger extends Logger{
    override def Log(msg: String): Unit = println(msg) //输出到哪里,目前是控制台
  }

  //3调用单例对象的实现方法
  def main(args: Array[String]): Unit = {
    val logger = new ConsoleLogger
    logger.info("aaaaa")
    logger.warn("sdasfaf")
    logger.error("zxsdsd")
  }
}

(4)对象混入trait

可以将trait混入到对象中,就是将trait中定义的方法,字段添加到一个对象中去
使用场景:是给一个对象可以额外的添加额外的方法(这种非侵入式编写方式类似于python的装饰器)

val/var 对象名 = new 类 with 特质
object ClassObject{
  //1.创建一个特质,实现方法log打印
  trait Logger{
    def log(msg:String) = println(msg)
  }
  //2.创建一个没有任何方法的类
  class UserService{

  }

  //3调用单例对象的实现方法
  def main(args: Array[String]): Unit = {
    val service = new UserService with Logger //非侵入式增加对象的额外方法
    service.log("hello Scala")
  }
}

(5)调用链模式

package com.yuge.scala.experence

object ClassObject{
  //1.定义一个HandLerTrait
  trait HandlerTrait{
    def handle(data:String) = {
      println("处理支付数据...")
    }
  }
  //2.定义两个trait(数据校验,签名校验)
  trait dataCheck extends HandlerTrait {
    override def handle(data: String): Unit = {
      println("数据校验...")
      super.handle(data)
    }

  }
  trait signatureCheck extends HandlerTrait{
    override def handle(data: String): Unit = {
      println("签名校验..")
      super.handle(data)
    }
  }
  //3.定义一个支付服务类,基础数据校验,签名校验
  /*
  注意这里通过with两个特质的关系是signatureCheck调用super就会进行dataCheck
  如果说是peyService虽然直接继承dataCheck内所有方法,但是如果是想要调用dataCheck进行执行,就必续通过signatureCheck的super调用,才可以实现,他们变成了一条由with串起来的链子
  */
  class payService extends dataCheck with signatureCheck{  
    override def handle(data: String): Unit = {
      println("准备支付...")
      super.handle(data)
    }
  }
  //4.创建支付服务对象,调用支付方法
  def main(args: Array[String]): Unit = {
    val service = new payService
    service.handle("支付数据数据")
  }
}

  • 返回结果
    准备支付…
    签名校验…
    数据校验…
    处理支付数据…
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值