大數據基礎-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 <- 1to3;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)
}

}

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)

在這裏插入代碼片

(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("支付數據數據")
  }
}

  • 返回結果
    準備支付…
    簽名校驗…
    數據校驗…
    處理支付數據…
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章