環境統一:
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)方法的調用
- 後綴調用法
對象名.方法名(參數)
Math.abs(-1)
- 中綴調用法
對象名 方法名 參數(如果參數有多個可以使用括號括起來)
Math abs -1
- 花括號調用
Math.abs{
//表達式1
//表達式2
}
注意:只能是方法僅有一個參數時,纔可以使用花括號調用法
- 無括號調用法
如果方法沒有參數,可以省略方法名後面的括號
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方法可以從集合獲取一個迭代器
- 迭代器的兩個基本操作
- hasNext:查詢容器中是否有下一個元素
- 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)定義伴生對象
- 定義一個 class 並在這裏面實現所有的實例成員。
- 添加一個 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)定義特質
- 定義
trait 名稱{
//抽象字段
//抽象方法
}
- 特質的繼承
class 類 extends 特質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("支付數據數據")
}
}
- 返回結果
準備支付…
簽名校驗…
數據校驗…
處理支付數據…