第 1 章 scala的概述1php
1.1 學習sdala的緣由 1java
1.2 Scala語言誕生小故事 1mysql
1.3 Scala 和 Java 以及 jvm 的關係分析圖 2linux
1.4 Scala語言的特色 3git
1.5 Windows下搭建Scala開發環境 4程序員
1.6 Linux下搭建Scala開發環境 5面試
1.7 Scala開發工具的介紹 8算法
1.7.1 idea工具的介紹 8sql
1.7.2 Scala插件安裝 8shell
1.8 scala的開發的快速入門 10
1.8.1 IDE工具Idea 來開發 「hello,world」 10
1.8.2 Scala程序反編譯-說明scala程序的執行流程 15
1.8.3 使用java寫了一段模擬的代碼 17
1.8.4 課堂小練習 18
1.8.5 Scala執行流程分析 18
1.8.6 Scala程序開發注意事項(重點) 19
1.9 Scala語言轉義字符 19
1.10 Scala語言輸出的三種方式 21
1.10.1 基本介紹 21
1.10.2 應用案例 21
1.11 Scala源碼的查看的關聯 22
1.12 註釋(comment) 23
1.12.1 介紹: 23
1.12.2 Scala中的註釋類型 23
1.12.3 文檔註釋的案例 24
1.13 規範的代碼風格 25
1.13.1 正確的註釋和註釋風格: 25
1.13.2 規範代碼的幾點要求 25
1.14 Scala官方編程指南 25
第 2 章 變量28
2.1 變量的介紹 28
2.1.1 概念 28
2.1.2 變量使用的基本步驟 28
2.2 Scala變量使用案例入門 28
2.3 Scala變量使用說明 29
2.3.1 變量聲明基本語法 29
2.3.2 注意事項 29
2.4 程序中 +號的使用 32
2.5 數據類型 33
2.5.1 scala數據類型的介紹 33
2.6 scala數據類型體系一覽圖 34
2.6.1 一覽圖 34
2.6.2 對scala數據類型體系總結 35
2.7 整數類型 36
2.7.1 基本介紹 36
2.7.2 整型的類型 36
2.7.3 應用案例 36
2.7.4 整型的使用細節 37
2.8 浮點類型 39
2.8.1 基本介紹 39
2.8.2 浮點型的分類 39
2.8.3 浮點型使用細節 39
2.9 字符類型(Char) 41
2.9.1 基本介紹 41
2.9.2 案例演示: 41
2.9.3 字符類型使用細節 41
2.9.4 字符類型本質探討 42
2.10 布爾類型:Boolean 43
2.10.1 基本介紹 43
2.11 Unit類型、Null類型和Nothing類型 43
2.11.1 基本說明 43
2.11.2 使用細節和注意事項 44
2.12 值類型轉換 45
2.12.1 值類型隱式轉換 45
2.12.2 高級隱式轉換和隱式函數 48
2.12.3 強制類型轉換 48
2.13 值類型轉換-課堂練習題 49
2.14 值類型和String類型的轉換 50
2.14.1 介紹 50
2.14.2 基本類型轉String類型 50
2.14.3 String類型轉基本數據類型 50
2.14.4 注意事項 51
2.15 標識符的命名規範 51
2.15.1 標識符概念 51
2.15.2 標識符的命名規則(記住) 51
2.15.3 標識符舉例說明 52
2.15.4 標識符命名注意事項 53
2.15.5 關鍵字介紹 53
第 3 章 運算符54
3.1 運算符介紹 54
3.2 算術運算符一覽 54
3.2.1 案例演示 54
3.2.2 細節說明 55
3.2.3 課堂練習 56
3.3 關係運算符(比較運算符) 57
3.3.1 一覽圖: 57
3.3.2 案例演示 58
3.3.3 細節說明 58
3.4 邏輯運算符 58
3.4.1 一覽圖 58
3.5 賦值運算符 59
3.5.1 位運算符 60
3.6 運算符的特別說明 61
3.7 運算符優先級 62
3.8 鍵盤輸入語句 63
3.8.1 介紹 63
3.8.2 步驟 : 63
3.8.3 案例演示: 64
第 4 章 流程控制67
4.1 分支控制if-else 67
4.1.1 分支控制if-else介紹 67
4.1.2 單分支 67
4.1.3 單分支對應流程圖 68
4.1.4 雙分支 68
4.1.5 多分支 70
4.1.6 分支控制if-else 注意事項 73
4.2 嵌套分支 75
4.2.1 基本介紹 75
4.2.2 基本語法 75
4.2.3 應用案例1 75
4.2.4 多分支的案例應用案例 76
4.3 switch分支結構 77
4.4 for循環控制 77
4.4.1 基本介紹 77
4.4.2 範圍數據循環方式1 77
4.4.3 範圍數據循環方式2 78
4.4.4 循環守衛 79
4.4.5 引入變量 80
4.4.6 嵌套循環 81
4.4.7 循環返回值 82
4.4.8 使用花括號{}代替小括號() 82
4.4.9 注意事項和細節說明 84
4.4.10 for循環練習題(學員先作) 85
4.5 while循環控制 86
4.5.1 基本語法 86
4.5.2 while循環應用實例 86
4.5.3 注意事項和細節說明 87
4.6 do..while循環控制 87
4.6.1 注意事項和細節說明 88
4.6.2 課堂練習題【學員先作】 88
4.7 多重循環控制 89
4.7.1 介紹: 89
4.7.2 應用實例: 89
4.8 while循環的中斷 92
4.8.1 基本說明 92
4.8.2 應用案例 92
4.8.3 課堂練習題: 94
第 5 章 函數式編程基礎96
5.1 函數式編程內容及授課順序說明 96
5.2 函數式編程授課順序即oop和函數式編程關係 96
5.2.1 幾個概念的說明 97
5.3 函數式編程介紹 98
5.4 爲何須要函數 98
5.5 函數介紹 98
5.5.1 基本語法 99
5.5.2 函數的快速入門 99
5.6 函數-調用機制 99
5.6.1 函數-調用過程 100
5.7 函數-遞歸調用 101
5.7.1 基本介紹 101
5.7.2 遞歸調用快速入門 101
5.7.3 函數遞歸須要遵照的重要原則: 102
5.7.4 遞歸課堂練習題 102
5.8 函數注意事項和細節討論 103
5.9 函數練習題 108
5.10 過程 109
5.10.1 基本介紹 109
5.10.2 案例說明: 109
5.11 惰性函數 110
5.11.1 看一個應用場景 110
5.11.2 畫圖說明[大數據推薦系統] 110
5.11.3 Java實現懶加載的代碼 110
5.11.4 介紹 111
5.11.5 案例演示 111
5.11.6 注意事項和細節 112
5.12 異常 112
5.12.1 介紹 113
5.12.2 Java異常處理回顧 113
5.12.3 Java異常處理的注意點. 113
5.12.4 Scala異常處理舉例 114
5.12.5 scala異常的小結和注意事項 114
5.13 函數的課堂練習題 115
第 6 章 面向對象編程基礎部分117
6.1 類與對象 117
6.1.1 看一個養貓貓問題 117
6.1.2 快速入門-面向對象的方式解決養貓問題 117
6.1.3 如何定義類 118
6.1.4 屬性 119
6.1.5 屬性的高級部分 121
6.1.6 如何建立對象 122
6.1.7 類和對象的內存分配機制 124
6.1.8 方法 125
6.1.9 課堂練習題 126
6.2 類與對象應用實例 128
6.2.1 小狗案例 128
6.3 構造器 130
6.3.1 看一個需求 130
6.3.2 回顧-Java構造器基本語法 131
6.3.3 回顧-Java構造器的特色 131
6.3.4 Scala構造器的介紹 132
6.3.5 Scala構造器的基本語法 132
6.3.6 快速入門 133
6.3.7 Scala構造器注意事項和細節 134
6.4 屬性高級 139
6.4.1 構造器參數 139
6.4.2 Bean屬性 141
6.5 對象建立的流程分析 143
6.5.1 看一個案例 143
6.5.2 流程分析(面試題) 143
第 7 章 面向對象編程(中級)145
7.1 包 145
7.1.1 看一個應用場景 145
7.1.2 回顧-Java包的三大做用 145
7.1.3 回顧-Java打包命令 145
7.1.4 打包的本質分析 146
7.1.5 快速入門 146
7.1.6 回顧-Java如何引入包 146
7.1.7 回顧-Java包的特色 147
7.1.8 Scala包的基本介紹 147
7.1.9 Scala包快速入門 147
7.1.10 Scala包的特色概述 147
7.1.11 Scala包的命名 149
7.1.12 Scala會自動引入的經常使用包 149
7.1.13 Scala包注意事項和使用細節 150
7.1.14 包對象 153
7.1.15 包對象的應用案例 154
7.1.16 包對象的注意事項 154
7.2 包的可見性 155
7.2.1 Scala中包的可見性介紹: 155
7.2.2 Scala中包的可見性和訪問修飾符的使用 155
7.3 包的引入 157
7.3.1 Scala引入包的細節和注意事項 157
7.4 面向對象編程方法-抽象 159
7.4.1 如何理解抽象 159
7.5 面向對象編程三大特徵 162
7.5.1 基本介紹 162
7.5.2 封裝介紹 162
7.5.3 封裝的理解和好處 163
7.5.4 如何體現封裝 163
7.5.5 封裝的實現步驟 163
7.5.6 快速入門案例 164
7.5.7 封裝的課堂練習題 165
7.5.8 Scala封裝的注意事項和細節 165
7.6 面向對象編程-繼承 166
7.6.1 Java繼承的簡單回顧 166
7.6.2 繼承基本介紹和示意圖 166
7.6.3 Scala繼承的基本語法 167
7.6.4 Scala繼承快速入門 167
7.6.5 Scala繼承給編程帶來的便利 169
7.6.6 子類繼承了什麼,怎麼繼承了? 169
7.6.7 重寫方法 171
7.6.8 Scala中類型檢查和轉換 172
7.6.9 Scala中超類的構造 177
7.6.10 覆寫字段 182
7.6.11 抽象類 187
7.6.12 Scala抽象類使用的注意事項和細節討論 189
7.6.13 匿名子類 190
7.6.14 課後練習題 192
第 8 章 面向對象編程-高級194
8.1 靜態屬性和方法 194
8.1.1 靜態屬性-提出問題 194
8.1.2 回顧下Java的靜態概念 194
8.1.3 Scala中靜態的概念-伴生對象 194
8.1.4 伴生對象的快速入門 195
8.1.5 伴生對象的小結 196
8.1.6 伴生對象解決小孩遊戲問題 198
8.1.7 apply方法的補充 199
8.2 單例對象 200
8.2.1 什麼是單例對象 200
8.2.2 回顧-Java單例對象 201
8.2.3 Scala中單例對象 203
8.2.4 單例模式的面試題 203
8.3 接口 204
8.3.1 回顧Java接口 204
8.3.2 Scala接口的介紹 205
8.4 特質(trait) 205
8.4.1 trait 的聲明 205
8.4.2 Scala中trait 的使用 206
8.4.3 特質的快速入門案例 206
8.4.4 特質trait 的再說明 209
8.4.5 帶有特質的對象,動態混入 211
8.4.6 scala建立對象的四種形式 214
8.4.7 疊加特質 214
8.4.8 在特質中重寫抽象方法 217
8.4.9 看成富接口使用的特質 220
8.4.10 特質中的具體字段 221
8.4.11 特質構造順序 221
8.4.12 擴展類的特質 222
8.4.13 自身類型 224
8.5 嵌套類 225
8.5.1 基本介紹 225
8.5.2 類型投影 229
8.6 數組的基本使用 230
第 9 章 隱式轉換和隱式參數232
9.1 隱式轉換 232
9.1.1 提出問題 232
9.1.2 隱式函數基本介紹 232
9.1.3 隱式函數快速入門 232
9.1.4 隱式函數的底層工做原理 233
9.1.5 隱式轉換的注意事項和細節 233
9.2 隱式轉換豐富類庫功能 234
9.2.1 基本介紹 234
9.2.2 分析解決方案 234
9.2.3 快速入門案例 234
9.3 隱式值 235
9.3.1 基本介紹 235
9.3.2 應用案例 235
9.3.3 課堂測試題 236
9.3.4 課堂練習 236
9.4 隱式類 237
9.4.1 基本介紹 237
9.4.2 隱式類使用有以下幾個特色: 238
9.4.3 應用案例 238
9.5 隱式的轉換時機 239
9.6 隱式解析機制 239
9.7 隱式轉換的前提 239
第 10 章 數據結構上-集合241
10.1 數據結構的特色 241
10.1.1 scala集合基本介紹 241
10.1.2 可變集合和不可變集合舉例 241
10.2 不可變集合繼承層次一覽 242
10.3 Scala可變集合繼承關係一覽圖 244
10.4 數組-定長數組(聲明泛型) 245
10.4.1 第一種方式定義數組 245
10.4.2 第二種方式定義數組 246
第 1 章 scala的概述
1.1 學習sdala的緣由
1.2 Scala語言誕生小故事
1.3 Scala 和 Java 以及 jvm 的關係分析圖
1.4 Scala語言的特色
Scala是一門以java虛擬機(JVM)爲運行環境並將面向對象和函數式編程的最佳特性結合在一塊兒
的靜態類型編程語言。
1) Scala 是一門多範式 (multi-paradigm) 的編程語言,Scala支持面向對象和函數式編程
2) Scala源代碼(.scala)會被編譯成Java字節碼(.class),而後運行於JVM之上,並能夠調用現有的Java類庫,實現兩種語言的無縫對接。[案例演示]
3) scala 單做爲一門語言來看, 很是的簡潔高效 (三元運算, ++ , --)
4) Scala 在設計時,馬丁·奧德斯基 是參考了Java的設計思想,能夠說Scala是源於java,同時馬丁·奧德斯基 也加入了本身的思想,將函數式編程語言的特色融合到JAVA中, 所以,對於學習過Java的同窗,只要在學習Scala的過程當中,搞清楚Scala 和 java相同點和不一樣點,就能夠快速的掌握Scala這門語言
5) 快速有效掌握Scala的三點建議 [1. 學習scala的特有的語法 2. 區別 scala和Java 3. 如何規範使用scala]
1.5 Windows下搭建Scala開發環境
具體的步驟
1) 首先把jdk1.8 安裝
2) 下載對應的scala安裝文件 scala-2.11.8.zip
3) 解壓 我這裏解壓到 d:/program
4) 配置scala 的環境變量
5) 測試一下, 輸入scala的指令看看效果
6) OK!
1.6 Linux下搭建Scala開發環境
在實際開發中,咱們的項目是部署到linux,所以,咱們須要在Linux下搭建scala的環境。
具體的步驟以下:
1) 下載對應的scala的安裝軟件.scala-2.11.8.tgz
2) 經過遠程登陸工具,將安裝軟件上傳到對應的linux系統(xshell5 xftp5)
3) mkdir /usr/local/scala 建立目錄
4) tar -xvzf scala-2.11.8.tgz && mv scala-2.11.8 /usr/local/scala/ 將安裝文件解壓,而且移動到 /usr/local/scala
5) 配置環境變量 vim /etc/profile
在該文件中配置 scala的bin目錄 /usr/local/scala/scala-2.11.8/bin
6) 測試一把
1) 介紹
上面打開的scala命令行窗口,咱們稱之爲REPL,是指:Read->Evaluation->Print->Loop,也稱之爲交互式解釋器。
2) 說明
在命令行窗口中輸入scala指令代碼時,解釋器會讀取指令代碼(R)並計算對應的值(E),而後將結果打印出來(P),接着循環等待用戶輸入指令(L)。從技術上講,這裏其實並非一個解釋器,而是指令代碼被快速的編譯成Java字節碼並被JVM加載執行。最終將執行結果輸出到命令行中
3) 示意圖
1.7 Scala開發工具的介紹
1.7.1 idea工具的介紹
1.7.2 Scala插件安裝
1) scala-intellij-bin-2017.2.6.zip
2) 建議該插件文件放到scala的安裝目錄
3) 將插件安裝到idea
4) 先找到安裝插件位置 file->setting...
5) 點擊ok->apply -> 重啓idea 便可
6) ok
1.8 scala的開發的快速入門
1.8.1 IDE工具Idea 來開發 「hello,world」
右鍵項目點擊-> add framework support... ,在下圖選擇scala
注意:若是是第一次引入框架,Use libary 看不到,須要配置, 配置就是選擇你的scala安裝目錄,而後工具就會自動識別,就會顯示user libary .
說明:右鍵main目錄->建立一個diretory -> 寫個名字(好比 scala)-> 右鍵scala 目錄->mark directory -> 選擇 source root 便可
運行後,就能夠看到輸出
1.8.2 Scala程序反編譯-說明scala程序的執行流程
//package com.atguigu.chapter01
//下面咱們說明一下scala程序的一執行流程 //分析 //1. object 在底層會生成兩個類 Hello , Hello$ //2. Hello 中有個main函數,調用 Hello$ 類的一個靜態對象 MODULES$ /* public final class Hello { public static void main(String[] paramArrayOfString) { Hello$.MODULE$.main(paramArrayOfString); } } */ //3. Hello$.MODULE$. 對象時靜態的,經過該對象調用Hello$的main函數 /* public void main(String[] args) { Predef..MODULE$.println("hello,scala"); } */ //4. 能夠理解咱們在main中寫的代碼在放在Hello$ 的main, 在底層執行scala編譯器作了一個包裝
object Hello { def main(args: Array[String]): Unit = { println("hello,scala") } }
|
1.8.3 使用java寫了一段模擬的代碼
package com.atguigu.chapter01;
public class Hello2 { public static void main(String[] args) { Hello2$.MODULE$.main(args); } }
final class Hello2$ { public static final Hello2$ MODULE$;
static { MODULE$ = new Hello2$(); }
public void main(String[] args) { System.out.println("hello,scala"); } //private Hello$() { MODULE$ = this; }
}
|
1.8.4 課堂小練習
1.8.5 Scala執行流程分析
1.8.6 Scala程序開發注意事項(重點)
1) Scala源文件以 「.scala" 爲擴展名。
2) Scala程序的執行入口是main()函數。
3) Scala語言嚴格區分大小寫。
4) Scala方法由一條條語句構成,每一個語句後不須要分號(Scala語言會在每行後自動加分號),這也體現出Scala的簡潔性。
5) 若是在同一行有多條語句,除了最後一條語句不須要分號,其它語句須要分號。
1.9 Scala語言轉義字符
scala的轉義字符。
輸出的結果:
C:\Users\Administrator\Desktop\SGG 韓順平 scala 核心編程\day01\筆記
k"kk
你好
hello
u
1.10 Scala語言輸出的三種方式
1.10.1 基本介紹
1) 字符串經過+號鏈接(相似java)。
2) printf用法 (相似C語言)字符串經過 % 傳值。
3) 字符串經過$引用(相似PHP)。
1.10.2 應用案例
package com.atguigu.chapter01.printdemo
object TestPrint { def main(args: Array[String]): Unit = { //使用+ var name : String = "tom" var sal : Double = 1.2 println("hello" + sal + name )
//使用格式化的方式printf printf("name=%s sal=%f\n", name, sal) //使用$引用的方式,輸出變量,相似php println(s"第三種方式 name=$name sal = $sal") } }
|
1.11 Scala源碼的查看的關聯
在使用scala過程當中,爲了搞清楚scala底層的機制,須要查看源碼,下面看看若是關聯和查看Scala的源碼包
1) 查看源碼, 選擇要查看的方法或者類, 輸入 ctrl + b
當咱們沒關聯源碼時,看到以下圖像:
2) 關聯源碼,看老師演示
步驟1:將咱們的源碼包拷貝到 scala/lib 文件夾下. scala-sources-2.12.4
步驟2: 關聯便可,選中這個文件夾,進行關聯, 最後,能夠看到源碼
1.12 註釋(comment)
1.12.1 介紹:
用於註解說明解釋程序的文字就是註釋,註釋提升了代碼的閱讀性;
註釋是一個程序員必需要具備的良好編程習慣。將本身的思想經過註釋先整理出來,再用代碼去體現。
1.12.2 Scala中的註釋類型
1) 單行註釋
2) 多行註釋
3) 文檔註釋
1.12.3 文檔註釋的案例
package com.atguigu.chapter01.comment2
object TestDemo {
/**
* @deprecated xxx
* @param args
*/
def main(args: Array[String]): Unit = {
//print("0k")
//ctrl +D ctrl +y
/*
println("ok1")
println("ok1")
println("ok1")
println("ok1")
println("ok1")
*/
println("ok")
}
}
1.13 規範的代碼風格
1.13.1 正確的註釋和註釋風格:
帶看Scala源碼
1.13.2 規範代碼的幾點要求
1) 正確的縮進和空白
2) 使用一次tab操做,實現縮進,默認總體向右邊移動,時候用shift+tab總體向左移
3) 或者使用 ctrl + alt + L 來進行格式化 [演示]
4) 運算符兩邊習慣性各加一個空格。好比:2 + 4 * 5。
5) 一行最長不超過80個字符,超過的請使用換行展現,儘可能保持格式優雅
1.14 Scala官方編程指南
還能夠根據須要檢索本身要查看的類或者函數。
第 2 章 變量
2.1 變量的介紹
2.1.1 概念
變量至關於內存中一個數據存儲空間的表示,你能夠把變量看作是一個房間的門
牌號,經過門牌號咱們能夠找到房間,而經過變量名能夠訪問到變量(值)。
2.1.2 變量使用的基本步驟
1) 聲明/定義變量 (scala要求變量聲明時初始化)
2) 使用
2.2 Scala變量使用案例入門
變量在內存中的佈局
2.3 Scala變量使用說明
2.3.1 變量聲明基本語法
var | val 變量名 [: 變量類型] = 變量值
說明:在scala中聲明一個變量時,能夠不指定類型,編譯器根據值肯定
2.3.2 注意事項
1) 聲明變量時,類型能夠省略(編譯器自動推導,即類型推導)
2) 類型肯定後,就不能修改,說明Scala 是強數據類型語言.
案例說明:
3) 在聲明/定義一個變量時,可使用var 或者 val 來修飾, var 修飾的變量可改變,val 修飾的變量不可改 [案例].
4) val修飾的變量在編譯後,等同於加上final經過反編譯看下底層代碼
對應的底層的.class是
5) var 修飾的對象引用能夠改變,val 修飾的則不可改變,但對象的狀態(值)倒是能夠改變的。(好比: 自定義對象、數組、集合等等) [分析val好處]
6) 變量聲明時,須要初始值
2.4 程序中 +號的使用
1) 當左右兩邊都是數值型時,則作加法運算
2) 當左右兩邊有一方爲字符串,則作拼接運
3) 案例演示:
2.5 數據類型
2.5.1 scala數據類型的介紹
1) Scala 與 Java有着相同的數據類型,在Scala中數據類型都是對象,也就是說scala沒有java中的原生類型
2) Scala數據類型分爲兩大類 AnyVal(值類型) 和 AnyRef(引用類型), 注意:無論是AnyVal仍是AnyRef 都是對象。[案例演示 Int , Char]
3) 相對於java的類型系統,scala要複雜些!也正是這複雜多變的類型系統才讓面向對象編程和函數式編程完美的融合在了一塊兒
2.6 scala數據類型體系一覽圖
2.6.1 一覽圖
2.6.2 對scala數據類型體系總結
1) scala中一切數據都是對象,都是Any的子類。
2) scala中數據類型分爲兩大類 值類型(AnyVal) , 引用類型(AnyRef),無論是值類型仍是引用類型都是對象。
3) scala數據類型仍然遵照低精度的值類型向高精度的值類型,自動轉換(隱式轉換)
4) scala中有兩個特殊的類型 Null , 它只有一個實例就是null, 在scala中,也叫bottom class
5) scala中有個特殊的類型 Nothing, 它是用於在一個函數沒有正常返回值使用 , 由於這樣咱們能夠把拋出的返回值,返回給任何的變量或者函數.
2.7 整數類型
2.7.1 基本介紹
Scala的整數類型就是用於存放整數值的,好比 12 , 30, 3456等等
2.7.2 整型的類型
數據類型 |
描述 |
Byte [1] |
8位有符號補碼整數。數值區間爲 -128 到 127 |
Short [2] |
16位有符號補碼整數。數值區間爲 -32768 到 32767 |
Int [4] |
32位有符號補碼整數。數值區間爲 -2147483648 到 2147483647 |
Long [8] |
64位有符號補碼整數。數值區間爲 -9223372036854775808 到 9223372036854775807 = 2的(64-1)次方-1 |
2.7.3 應用案例
2.7.4 整型的使用細節
1) Scala各整數類型有固定的表數範圍和字段長度,不受具體OS的影響,以保證Scala程序的可移植性。
2) Scala的整型 常量/字面量 默認爲 Int 型,聲明Long型 常量/字面量 須後加‘l’’或‘L’ [反編譯看]
反編譯後的字節碼文件
3) Scala程序中變量常聲明爲Int型,除非不足以表示大數,才使用Long
2.8 浮點類型
2.8.1 基本介紹
Scala的浮點類型能夠表示一個小數,好比 123.4f,7.8 ,0.12等等
2.8.2 浮點型的分類
Float [4] |
32 位, IEEE 754標準的單精度浮點數 |
Double [8] |
64 位 IEEE 754標準的雙精度浮點數 |
2.8.3 浮點型使用細節
package com.atguigu.chapter01.floattest
object FloatDemo { def main(args: Array[String]): Unit = {
var n1 = 5.12E2 //5.12 * 10的2次方 println("n1=" + n1) var n2 = 5.12e-2 // 5.12 / 10的2次方 println("n2=" + n2)
//建議,在開發中須要高精度小數時,請選擇Double var n3 = 2.2345678912f // var n4 = 2.2345678912 println("n3=" + n3) println("n4=" + n4)
//運行的結果 /* n1=512.0 n2=0.0512 n3=2.2345679 n4=2.2345678912 */
} }
|
2.9 字符類型(Char)
2.9.1 基本介紹
字符類型能夠表示單個字符,字符類型是Char, 16位無符號Unicode字符(2個字節), 區間值爲 U+0000 到 U+FFFF
2.9.2 案例演示:
2.9.3 字符類型使用細節
1) 字符常量是用單引號(‘ ’)括起來的單個字符。例如:var c1 = 'a‘ var c2 = '中‘ var c3 = '9'
2) Scala 也容許使用轉義字符‘\’來將其後的字符轉變爲特殊字符型常量。例如:var c3 = ‘\n’ // '\n'表示換行符
3)能夠直接給Char賦一個整數,而後輸出時,會按照對應的unicode 字符輸出 ['\u0061' 97]
4) Char類型是能夠進行運算的,至關於一個整數,由於它都對應有Unicode碼.
2.9.4 字符類型本質探討
1) 字符型 存儲到 計算機中,須要將字符對應的碼值(整數)找出來
存儲:字符——>碼值——>二進制——>存儲
讀取:二進制——>碼值——> 字符——>讀取
2) 字符和碼值的對應關係是經過字符編碼表決定的(是規定好), 這一點和Java同樣。
2.10 布爾類型:Boolean
2.10.1 基本介紹
1) 布爾類型也叫Boolean類型,Booolean類型數據只容許取值true和false
2) boolean類型佔1個字節。
3) boolean 類型適於邏輯運算,通常用於程序流程控制[後面詳解]:
2.11 Unit類型、Null類型和Nothing類型
2.11.1 基本說明
Unit |
表示無值,和其餘語言中void等同。用做不返回任何結果的方法的結果類型。Unit只有一個實例值,寫成()。 |
Null |
null , Null 類型只有一個實例值 null |
Nothing |
Nothing類型在Scala的類層級的最低端;它是任何其餘類型的子類型。 當一個函數,咱們肯定沒有正常的返回值,能夠用Nothing 來指定返回類型,這樣有一個好處,就是咱們能夠把返回的值(異常)賦給其它的函數或者變量(兼容性) |
2.11.2 使用細節和注意事項
1) Null類只有一個實例對象,null,相似於Java中的null引用。null能夠賦值給任意引用類型(AnyRef),可是不能賦值給值類型(AnyVal: 好比 Int, Float, Char, Boolean, Long, Double, Byte, Short)
2) Unit類型用來標識過程,也就是沒有明確返回值的函數。
因而可知,Unit相似於Java裏的void。Unit只有一個實例,
(),這個實例也沒有實質的意義
3) Nothing,能夠做爲沒有正常返回值的方法的返回類型,很是直觀的告訴你這個方法不會正常返回,並且因爲Nothing是其餘任意類型的子類,他還能跟要求返回值的方法兼容。
2.12 值類型轉換
2.12.1 值類型隱式轉換
當Scala程序在進行賦值或者運算時,精度小的類型自動轉換爲精度大的數據類型,這個就是自動類型轉換(隱式轉換)。
演示一下基本數據類型轉換的基本狀況。
自動類型轉換細節說明
1) 有多種類型的數據混合運算時,系統首先自動將全部數據轉換成容量最大的那種數據類型,而後再進行計算。
2) 當咱們把精度(容量)大 的數據類型賦值給精度(容量)小 的數據類型時,就會報錯,反之就會進行自動類型轉換。
3) (byte, short) 和 char之間不會相互自動轉換。
4) byte,short,char 他們三者能夠計算,在計算時首先轉換爲int類型。
5) 自動提高原則: 表達式結果的類型自動提高爲 操做數中最大的類型
package com.atguigu.chapter02.transtest
object TransferDemo { def main(args: Array[String]): Unit = {
var n = 1 + 2.0 println(n) // n 就是Double
//當咱們把精度(容量)大 的數據類型賦值給精度(容量)小 的數據類型時,就會報錯 var n2 : Long = 1L //var n3 : Int = n2 //錯誤,緣由不能把高精度的數據直接賦值和低精度。
//(byte, short) 和 char之間不會相互自動轉換 var n4 : Byte = 1 //var c1 : Char = n4 錯
//byte,short,char 他們三者能夠計算,在計算時首先轉換爲int類型
var n5 : Byte = 1 var c2 : Char = 1 // var n : Short = n5 + c2 //當n5 + c2 結果類型就是int // var n6 : Short = 10 + 90 //錯誤 var n7 : Short = 100 //√
} }
|
2.12.2 高級隱式轉換和隱式函數
2.12.3 強制類型轉換
自動類型轉換的逆過程,將容量大的數據類型轉換爲容量小的數據類型。使用時要加上強制轉函數,但可能形成精度下降或溢出,格外要注意。
java : int num = (int)2.5
scala : var num : Int = 2.7.toInt
1) 當進行數據的 從 大——>小,就須要使用到強制轉換
2) 強轉符號只針對於最近的操做數有效,每每會使用小括號提高優先級
3) Char類型能夠保存 Int的常量值,但不能保存Int的變量值,須要強轉
4) Byte和Short類型在進行運算時,當作Int類型處理。
2.13 值類型轉換-課堂練習題
2.14 值類型和String類型的轉換
2.14.1 介紹
在程序開發中,咱們常常須要將基本數據類型轉成String 類型。或者將String類型轉成基本數據類型。
2.14.2 基本類型轉String類型
語法: 將基本類型的值+"" 便可
案例演示
2.14.3 String類型轉基本數據類型
案例說明:
2.14.4 注意事項
1) 在將String 類型轉成 基本數據類型時,要確保String類型可以轉成有效的數據,好比 咱們能夠把 "123" , 轉成一個整數,可是不能把 "hello" 轉成一個整數
2) 思考就是要把 "12.5" 轉成 Int ? // 錯誤,在轉換中,不會使用截取
2.15 標識符的命名規範
2.15.1 標識符概念
Scala 對各類變量、方法、函數等命名時使用的字符序列稱爲標識符
凡是本身能夠起名字的地方都叫標識符
2.15.2 標識符的命名規則(記住)
1) Scala中的標識符聲明,基本和Java是一致的,可是細節上會有所變化。
2) 首字符爲字母,後續字符任意字母和數字,美圓符號,可後接下劃線_
3) 數字不能夠開頭。
4) 首字符爲操做符(好比+ - * / ),後續字符也需跟操做符 ,至少一個(反編譯)
5) 操做符(好比+-*/)不能在標識符中間和最後.
6) 用反引號`....`包括的任意字符串,即便是關鍵字(39個)也能夠 [true]
案例:
2.15.3 標識符舉例說明
hello // ok
hello12 // ok
1hello // error
h-b // error
x h // error
h_4 // ok
_ab // ok
Int // ok , 由於在scala Int 是預約義的字符
Float // ok
_ // error ,由於在scala _ 有不少其餘的做用。
Abc // ok
+*- // ok
+a // error
2.15.4 標識符命名注意事項
1) 包名:儘可能採起有意義的包名,簡短,有意義
2) 變量名、函數名 、方法名 採用駝峯法。
2.15.5 關鍵字介紹
Scala有39個關鍵字:
package, import, class, object, trait, extends, with, type, forSome
private, protected, abstract, sealed, final, implicit, lazy, override
try, catch, finally, throw
if, else, match, case, do, while, for, return, yield
def, val, var
this, super
new
true, false, null
第 3 章 運算符
3.1 運算符介紹
運算符是一種特殊的符號,用以表示數據的運算、賦值和比較等。
1) 算術運算符
2) 賦值運算符
3) 比較運算符(關係運算符)
4) 邏輯運算符
5) 位運算符
3.2 算術運算符一覽
3.2.1 案例演示
案例演示算術運算符的使用(Operator.scala)。
+, - , * , / , % 重點講解 /、%
+、-、* 是一個道理,徹底能夠類推。
算數運算符的運算規則和Java同樣
案例:
3.2.2 細節說明
1) 對於除號「/」,它的整數除和小數除是有區別的:整數之間作除法時,只保留整數部分而捨棄小數部分。 例如:var x : Int = 10/3 ,結果是 3
2) 當對一個數取模時,能夠等價 a%b=a-a/b*b , 這樣咱們能夠看到 取模的一個本質運算(和java 的取模規則同樣)。
3) 注意:Scala中沒有++、--操做符,須要經過+=、-=來實現一樣的效果
4) 案例
3.2.3 課堂練習
假如還有97天放假,問:xx個星期零xx天
定義一個變量保存華氏溫度,華氏溫度轉換攝氏溫度的公式爲:5/9*(華氏溫度-100),請求出華氏溫度對應的攝氏溫度。[測試:232.5]
3.3 關係運算符(比較運算符)
3.3.1 一覽圖:
3.3.2 案例演示
3.3.3 細節說明
1) 關係運算符的結果都是Boolean型,也就是要麼是true,要麼是false。
2) 關係運算符組成的表達式,咱們稱爲關係表達式。 a > b
3) 比較運算符「==」不能誤寫成「=」
4) 使用陷阱: 若是兩個浮點數進行比較,應當保證數據類型一致.
3.4 邏輯運算符
3.4.1 一覽圖
3.5 賦值運算符
3.5.1 位運算符
3.6 運算符的特別說明
Scala不支持三目運算符 , 在Scala 中使用 if – else 的方式實現。
課堂練習
1) 案例1:求兩個數的最大值
2) 案例2:求三個數的最大值
3.7 運算符優先級
3.8 鍵盤輸入語句
3.8.1 介紹
在編程中,須要接收用戶輸入的數據,就可使用鍵盤輸入語句來獲取。InputDemo.scala
3.8.2 步驟 :
導入該類的所在包
建立該類對象(聲明變量)
調用裏面的功能
3.8.3 案例演示:
要求:能夠從控制檯接收用戶信息,【姓名,年齡,薪水】。
1) 回顧Java的實現
2) Scala的實現
使用java模擬一下爲何能夠經過object的名字,直接調用其方法.
第 4 章 流程控制
4.1 分支控制if-else
4.1.1 分支控制if-else介紹
讓程序有選擇的的執行,分支控制有三種:
單分支
雙分支
多分支
4.1.2 單分支
if (條件表達式) {
執行代碼塊
}
說明:當條件表達式爲ture 時,就會執行 { } 的代碼。
請你們看個案例[IfDemo.scala]:
編寫一個程序,能夠輸入人的年齡,若是該同志的年齡大於18歲,則輸出 「age > 18」
4.1.3 單分支對應流程圖
4.1.4 雙分支
if (條件表達式) {
執行代碼塊1
} else {
執行代碼塊2
}
請你們看個案例[IfDemo2.scala]:
編寫一個程序,能夠輸入人的年齡,若是該同志的年齡大於18歲,則輸出 「age >18」。不然 ,輸出 「 age <= 18 」, 本身寫。
練習題:
4.1.5 多分支
if (條件表達式1) {
執行代碼塊1
}
else if (條件表達式2) {
執行代碼塊2
}
……
else {
執行代碼塊n
}
請你們看個案例[IfDemo3.scala]:
嶽小鵬參加scala考試,他和父親嶽不羣達成承諾:
若是:
成績爲100分時,獎勵一輛BMW;
成績爲(80,99]時,獎勵一臺iphone7plus;
當成績爲[60,80]時,獎勵一個 iPad;
其它時,什麼獎勵也沒有。
說明: 成績在程序中指定!
代碼以下:
求ax2+bx+c=0方程的根。a,b,c分別爲函數的參數,若是:b2-4ac>0,則有兩個解;
b2-4ac=0,則有一個解;b2-4ac<0,則無解; [a=3 b=100 c=6]
提示1:x1=(-b+sqrt(b2-4ac))/2a
X2=(-b-sqrt(b2-4ac))/2a
提示2:sqrt(num) 在 scala 包中(默認引入的) 的math 的包對象有不少方法直接可用.
//分析1. 多分支 2. 2. b2-4ac 計算出保存到一個變量 3. 引入math.sqrt
//走代碼。
4.1.6 分支控制if-else 注意事項
1) 若是大括號{}內的邏輯代碼只有一行,大括號能夠省略, 這點和java 的規定同樣。
2) Scala中任意表達式都是有返回值的,也就意味着if else表達式實際上是有返回結果的,具體返回結果的值取決於知足條件的代碼體的最後一行內容.[案例演示]
3) Scala中是沒有三元運算符,由於能夠這樣簡寫
4) 案例演示
4.2 嵌套分支
4.2.1 基本介紹
在一個分支結構中又完整的嵌套了另外一個完整的分支結構,裏面的分支的結構稱爲內層分支外面的分支結構稱爲外層分支。嵌套分支不要超過3層
4.2.2 基本語法
if(){
if(){
}else{
}
}
4.2.3 應用案例1
參加百米運動會,若是用時8秒之內進入決賽,不然提示淘汰。而且根據性別提示進入男子組或女子組。【可讓學員先練習下5min】, 輸入成績和性別,進行判斷。1分鐘思考思路
double second; char gender;
4.2.4 多分支的案例應用案例
4.3 switch分支結構
在scala中沒有switch,而是使用模式匹配來處理。
模式匹配涉及到的知識點較爲綜合,所以咱們放在後面講解
4.4 for循環控制
4.4.1 基本介紹
Scala 也爲for 循環這一常見的控制結構提供了很是多的特性,這些for 循環的特性被稱爲for 推導式(for comprehension)或for 表達式(for expression)
4.4.2 範圍數據循環方式1
for(i <- 1 to 3){
print(i + " ")
}
println()
1) i 表示循環的變量, <- 規定好 to 規定
2) i 將會從 1-3 循環, 先後閉合
3) 輸出10句 "hello,SGG!"
4.4.3 範圍數據循環方式2
for(i <- 1 until 3) {
print(i + " ")
}
println()
說明:
1) 這種方式和前面的區別在於 i 是從1 到 3-1
2) 即便前閉合後開的範圍
3) 輸出10句 "hello,SGG!"
for ( int i = 0; i < arr.lenght(); i++) {
}
4.4.4 循環守衛
for(i <- 1 to 3 if i != 2) {
print(i + " ")
}
println()
1) 循環守衛,即循環保護式(也稱條件判斷式,守衛)。保護式爲true則進入循環體內部,爲false則跳過,相似於continue
2) 上面的代碼等價
for (i <- 1 to 3){
if (i != 2) {
print(i + "")
}
}
4.4.5 引入變量
for(i <- 1 to 3; j = 4 - i) {
print(j + " ")
}
1) 沒有關鍵字,因此範圍後必定要加;來隔斷邏輯
2) 上面的代碼等價
4.4.6 嵌套循環
for(i <- 1 to 3; j <- 1 to 3) {
println(" i =" + i + " j = " + j)
}
1) 沒有關鍵字,因此範圍後必定要加;來隔斷邏輯
2) 上面的代碼等價
3) 案例
4.4.7 循環返回值
val res = for(i <- 1 to 10) yield i
println(res)
將遍歷過程當中處理的結果返回到一個新Vector集合中,使用yield關鍵字
Vector(2, 4, 6, 8, 10, 12, 14, 16, 18, 20)
4.4.8 使用花括號{}代替小括號()
for(i <- 1 to 3; j = i * 2) {
println(" i= " + i + " j= " + j)
}
for{
i <- 1 to 3
j = i * 2} {
println(" i= " + i + " j= " + j)
}
1) {}和()對於for表達式來講均可以
2) for 推導式有一個不成文的約定:當for 推導式僅包含單一表達式時使用圓括號,當其包含多個表達式時使用大括號
3) 當使用{} 來換行寫表達式時,分號就不用寫了
4) 案例
4.4.9 注意事項和細節說明
1) scala 的for循環形式和java是較大差別,這點請同窗們注意,可是基本的原理仍是同樣的。
2) scala 的for循環是表達式,是有返回值的。java的for循環不是表達式,沒有返回值.
3) scala 的for循環的步長如何控制! [for(i <- Range(1,3,2)]
4.4.10 for循環練習題(學員先作)
1) 打印1~100之間全部是9的倍數的整數的個數及總和.
2) 完成下面的表達式輸出
4.5 while循環控制
4.5.1 基本語法
循環變量初始化
while (循環條件) {
循環體(語句)
循環變量迭代
}
4.5.2 while循環應用實例
畫出流程圖
輸出10句"你好,SGG"
4.5.3 注意事項和細節說明
1) 循環條件是返回一個布爾值的表達式
2) while循環是先判斷再執行語句
3) 與If語句不一樣,While語句自己沒有值,即整個While語句的結果是Unit類型的()
4) 由於while中沒有返回值,因此當要用該語句來計算並返回結果時,就不可避免的使用變量 ,而變量須要聲明在while循環的外部,那麼就等同於循環的內部對外部的變量形成了影響, 也就違背了函數式編程的重要思想(純函數思想),因此不推薦使用,而是推薦使用for循環。
4.6 do..while循環控制
4.6.1 注意事項和細節說明
1) 循環條件是返回一個布爾值的表達式
2) do..while循環是先執行,再判斷
3) 和while 同樣,由於do…while中沒有返回值,因此當要用該語句來計算並返回結果時,就不可避免的使用變量 ,而變量須要聲明在do...while循環的外部,那麼就等同於循環的內部對外部的變量形成了影響, 也就違背了函數式編程的重要思想(純函數思想),因此不推薦使用,而是推薦使用for循環
4.6.2 課堂練習題【學員先作】
1) 計算1—100的和 【課後】
2) 統計1——200之間能被5整除但不能被3整除的個數 【課堂】
4.7 多重循環控制
4.7.1 介紹:
1) 將一個循環放在另外一個循環體內,就造成了嵌套循環。其中,for ,while ,do…while都可以做爲外層循環和內層循環。【建議通常使用兩層,最多不要超過3層】
2) 實質上,嵌套循環就是把內層循環當成外層循環的循環體。當只有內層循環的循環條件爲false時,纔會徹底跳出內層循環,纔可結束外層的當次循環,開始下一次的循環。
3) 設外層循環次數爲m次,內層爲n次, 則內層循環體實際上須要執行m*n=mn次。
4.7.2 應用實例:
1) 統計三個班成績狀況,每一個班有5名同窗,求出各個班的平均分和全部班級的平均分[學生的成績從鍵盤輸入]。
package com.atguigu.chapter03.opertest.exer import scala.io._ object Mulforexam { def main(args: Array[String]): Unit = { /* 統計三個班成績狀況,每一個班有5名同窗, 求出各個班的平均分和全部班級的平均分[學生的成績從鍵盤輸入]。 分析: 1. 班級個數 classNum, 學生個數 sutNum, 總分 totalFen, 每一個班級的總分 sum 2. 使用雙層循環 */ val classNum = 3 val sutNum = 5 var totalFen = 0.0 var fen = 0.0 var sum = 0.0 for (i <- 1 to classNum) { sum = 0.0 //每一個班級的總分 for (j <- 1 to sutNum) { printf("請輸入第%d個班的第%d學生的成績\n", i, j) fen = StdIn.readDouble() sum += fen } //sum 就是i班級總分 totalFen += sum printf("第%d個班級的平均分是%.2f \n", i, (sum / sutNum))
} printf("全部學生的平均分是%.2f \n", totalFen / (sutNum * classNum))
}
}
|
2) 統計三個班及格人數,每一個班有5名同窗。
在第一個案例的基礎上調整便可:
3) 打印出九九乘法表
4.8 while循環的中斷
4.8.1 基本說明
Scala內置控制結構特意去掉了break和continue,是爲了更好的適應函數式編程,推薦使用函數式的風格解決break和contine的功能,而不是一個關鍵字。
4.8.2 應用案例
對代碼的總結
1) 在break() 函數 代碼是
def break(): Nothing = { throw breakException }
2) breakable(op: =>Unit) 函數, 是一個高階函數,能夠接受另一個函數或者一段並執行,並處理若是捕獲到breakException, 就 throw ex
def breakable(op: => Unit) {
try {
op
} catch {
case ex: BreakControl =>
if (ex ne breakException) throw ex
}
}
3) 從這裏看到,咱們的while循環就是傳入的代碼,能夠被breakable執行。
4) scala中有這個風格,若是咱們傳入的是參數【代碼】,是多行的,則咱們的可使用{} 替代()
5) 在scala若是要使用continue的邏輯,則使用if-else 來處理。
6) 在for循環中,同樣可使用breakable( break() )
4.8.3 課堂練習題:
1) 100之內的數求和,求出 當和 第一次大於20的當前數【for】
2) 實現登陸驗證,有三次機會,若是用戶名爲」張無忌」 ,密碼」888」提示登陸成功,不然提示還有幾回機會,請使用for 循環完成
第 5 章 函數式編程基礎
5.1 函數式編程內容及授課順序說明
5.2 函數式編程授課順序即oop和函數式編程關係
5.2.1 幾個概念的說明
在學習Scala中將方法、函數、函數式編程和麪向對象編程明確一下:
1) 在scala中,方法和函數幾乎能夠等同(好比他們的定義、使用、運行機制都同樣的),只是函數的使用方式更加的靈活多樣。
2) 函數式編程是從編程方式(範式)的角度來談的,能夠這樣理解函數式編程把函數當作一等公民,充分利用函數 支持的函數的多種使用方式。
好比:
在Scala當中,函數是一等公民,像變量同樣,既能夠做爲函數的參數使用,也能夠將函數賦值給一個變量. ,函數的建立不用依賴於類或者對象,而在Java當中,函數的建立則要依賴於類、抽象類或者接口.
3) 面向對象編程是以對象爲基礎的編程方式。
4) 在scala中函數式編程和麪向對象編程融合在一塊兒了。
5.3 函數式編程介紹
5.4 爲何須要函數
請你們完成這樣一個需求:
輸入兩個數,再輸入一個運算符(+,-,*,/),獲得結果.。
先使用傳統的方式來解決,看看有什麼問題沒有?
1) 代碼冗餘
2) 不利於代碼的維護
5.5 函數介紹
爲完成某一功能的程序指令(語句)的集合,稱爲函數
5.5.1 基本語法
5.5.2 函數的快速入門
5.6 函數-調用機制
5.6.1 函數-調用過程
5.7 函數-遞歸調用
5.7.1 基本介紹
一個函數在函數體內又調用了自己,咱們稱爲遞歸調用
5.7.2 遞歸調用快速入門
5.7.3 函數遞歸須要遵照的重要原則:
1) 執行一個函數時,就建立一個新的受保護的獨立空間(新函數棧)
2) 函數的局部變量是獨立的,不會相互影響
3) 遞歸必須向退出遞歸的條件逼近,不然就是無限遞歸,死龜了:)
4) 當一個函數執行完畢,或者遇到return,就會返回,遵照誰調用,就將結果返回給誰,同時當函數執行完畢或者返回時,該函數棧自己也會被系統銷燬
5.7.4 遞歸課堂練習題
5.8 函數注意事項和細節討論
1) 函數的形參列表能夠是多個,函數沒有形參,調用時 能夠不帶()
2) 形參列表和返回值列表的數據類型能夠是值類型和引用類型。【案例演示】
3) Scala中的函數能夠根據函數體最後一行代碼自行推斷函數返回值類型。那麼在這種狀況下,return關鍵字能夠省略 [前面咱們講快速入門說過]
4) 由於Scala能夠自行推斷,因此在省略return關鍵字的場合,返回值類型也能夠省略
5) 若是函數明確使用return關鍵字,那麼函數返回就不能使用自行推斷了,這時要明確寫成 : 返回類型 = ,固然若是你什麼都不寫,即便有return 返回值爲()
6) 若是函數明確聲明無返回值(聲明Unit),那麼函數體中即便使用return關鍵字也不會有返回值
7) 若是明確函數無返回值或不肯定返回值類型,那麼返回值類型能夠省略(或聲明爲Any)
8) Scala語法中任何的語法結構均可以嵌套其餘語法結構,即:函數中能夠再聲明/定義函數,類中能夠再聲明類 ,方法中能夠再聲明/定義方法
9) Scala函數的形參,在聲明參數時,直接賦初始值(默認值),這時調用函數時,若是沒有指定實參,則會使用默認值。若是指定了實參,則實參會覆蓋默認值
10) 若是函數存在多個參數,每個參數均可以設定默認值,那麼這個時候,傳遞的參數究竟是覆蓋默認值,仍是賦值給沒有默認值的參數,就不肯定了(默認按照聲明順序[從左到右])。在這種狀況下,能夠採用帶名參數 [案例演示+練習]
11) scala 函數的形參默認是val的,所以不能在函數中進行修改.
12) 遞歸函數未執行以前是沒法推斷出來結果類型,在使用時必須有明確的返回值類型
13) Scala函數支持可變參數
//支持0到多個參數
def sum(args :Int*) : Int = {
}
//支持1到多個參數
def sum(n1: Int, args: Int*) : Int = {
}
說明:
1) args 是集合, 經過 for循環 能夠訪問到各個值。
2) 案例演示: 編寫一個函數sum ,能夠求出 1到多個int的和
5.9 函數練習題
5.10 過程
5.10.1 基本介紹
將函數的返回類型爲Unit的函數稱之爲過程(procedure),若是明確函數沒有返回值,那麼等號能夠省略
5.10.2 案例說明:
5.11 惰性函數
5.11.1 看一個應用場景
惰性計算(儘量延遲表達式求值)是許多函數式編程語言的特性。惰性集合在須要時提供其元素,無需預先計算它們,這帶來了一些好處。首先,您能夠將耗時的計算推遲到絕對須要的時候。其次,您能夠創造無限個集合,只要它們繼續收到請求,就會繼續提供元素。函數的惰性使用讓您可以獲得更高效的代碼。Java 並無爲惰性提供原生支持,Scala提供了。
5.11.2 畫圖說明[大數據推薦系統]
5.11.3 Java實現懶加載的代碼
5.11.4 介紹
當函數返回值被聲明爲lazy時,函數的執行將被推遲,直到咱們首次對此取值,該函數纔會執行。這種函數咱們稱之爲惰性函數,在Java的某些框架代碼中稱之爲懶加載(延遲加載)。
5.11.5 案例演示
看老師演示+反編譯
5.11.6 注意事項和細節
1) lazy 不能修飾 var 類型的變量
2) 不可是 在調用函數時,加了 lazy ,會致使函數的執行被推遲,咱們在聲明一個變量時,若是給聲明瞭 lazy ,那麼變量值得分配也會推遲。 好比 lazy val i = 10
5.12 異常
5.12.1 介紹
1) Scala提供try和catch塊來處理異常。try塊用於包含可能出錯的代碼。catch塊用於處理try塊中發生的異常。能夠根據須要在程序中有任意數量的try...catch塊。
2) 語法處理上和Java相似,可是又不盡相同
5.12.2 Java異常處理回顧
5.12.3 Java異常處理的注意點.
1) java語言按照try—catch—finally的方式來處理異常
2) 無論有沒有異常捕獲,都會執行finally, 所以一般能夠在finally代碼塊中釋放資源
3) 能夠有多個catch,分別捕獲對應的異常,這時須要把範圍小的異常類寫在前面,把範圍大的異常類寫在後面,不然編譯錯誤。會提示 "Exception 'java.lang.xxxxxx' has already been caught"【案例演示】
5.12.4 Scala異常處理舉例
5.12.5 scala異常的小結和注意事項
1) 咱們將可疑代碼封裝在try塊中。 在try塊以後使用了一個catch處理程序來捕獲異常。若是發生任何異常,catch處理程序將處理它,程序將不會異常終止。
2) Scala的異常的工做機制和Java同樣,可是Scala沒有「checked(編譯期)」異常,即Scala沒有編譯異常這個概念,異常都是在運行的時候捕獲處理。
3) 用throw關鍵字,拋出一個異常對象。全部異常都是Throwable的子類型。throw表達式是有類型的,就是Nothing,由於Nothing是全部類型的子類型,因此throw表達式能夠用在須要類型的地方
4) 在Scala裏,借用了模式匹配的思想來作異常的匹配,所以,在catch的代碼裏,是一系列case子句來匹配異常。【前面案例能夠看出這個特色, 模式匹配咱們後面詳解】,當匹配上後 => 有多條語句能夠換行寫,相似 java 的 switch case x: 代碼塊..
5) 異常捕捉的機制與其餘語言中同樣,若是有異常發生,catch子句是按次序捕捉的。所以,在catch子句中,越具體的異常越要靠前,越廣泛的異常越靠後,若是把越廣泛的異常寫在前,把具體的異常寫在後,在scala中也不會報錯,但這樣是很是很差的編程風格。
6) finally子句用於執行無論是正常處理仍是有異常發生時都須要執行的步驟,通常用於對象的清理工做,這點和Java同樣。
7) Scala提供了throws關鍵字來聲明異常。可使用方法定義聲明異常。 它向調用者函數提供了此方法可能引起此異常的信息。 它有助於調用函數處理並將該代碼包含在try-catch塊中,以免程序異常終止。在scala中,可使用throws註釋來聲明異常
5.13 函數的課堂練習題
編寫一個函數,從終端輸入一個整數(1—9),打印出對應的乘法表
第 6 章 面向對象編程基礎部分
6.1 類與對象
6.1.1 看一個養貓貓問題
張老太養了兩隻貓貓:一隻名字叫小白,今年3歲,白色。還有一隻叫小花,今年100歲,花色。請編寫一個程序,當用戶輸入小貓的名字時,就顯示該貓的名字,年齡,顏色。若是用戶輸入的小貓名錯誤,則顯示 張老太沒有這隻貓貓。
貓有三種數據(屬性) è 使用變量很差用
須要的數據類型
1.存儲不一樣數據類型數據。
2.能夠對這些數據進行操做
3.類
6.1.2 快速入門-面向對象的方式解決養貓問題
6.1.3 如何定義類
[修飾符] class 類名 {
類體
}
1) scala語法中,類並不聲明爲public,全部這些類都具備公有可見性(即默認就是public),[修飾符在後面再詳解].
2) 一個Scala源文件能夠包含多個類.
6.1.4 屬性
屬性是類的一個組成部分,通常是值數據類型,也但是引用類型。好比咱們前面定義貓類 的 age 就是屬性
案例代碼:
package com.atguigu.chapter06.Demo
object Test01 { def main(args: Array[String]): Unit = { //建立一個Cat對象 var cat : Cat = new Cat() var cat2 = new Cat() // 這裏的.name 並非直接訪問屬性,而是經過一個public方法訪問.(講解屬性時,再剖析) cat2.name = "tom貓" //public void name_$eq(String x$1) { this.name = x$1; } cat2.age = 3 cat2.color = "黑色" println("cat2.name=" + cat2.name)// public String name() var tiger = new Tiger() cat2.boss = tiger println("cat2.boss.name=" + cat2.boss.name) //cat2.boss().name() } } class Cat { //若是這裏是class 類 ,在底層只有一個類Cat //三個屬性 var name: String = "" // 在底層,會生成相似java的 setter [xx_$eq] getter [xxxx()] var age: Int = 0 var color: String = "" var boss: Tiger = _ // _ 表示給屬性一個默認值
}
class Tiger{ // 對應一個 Tiger.class var name = "華南虎~" }
|
6.1.5 屬性的高級部分
6.1.6 如何建立對象
val | var 對象名 [:類型] = new 類型()
1) 若是咱們不但願改變對象的引用(即:內存地址), 應該聲明爲val 性質的,不然聲明爲var, scala設計者推薦使用val ,由於通常來講,在程序中,咱們只是改變對象屬性的值,而不是改變對象的引用
2) scala在聲明對象變量時,能夠根據建立對象的類型自動推斷,因此類型聲明能夠省略,但當類型和後面new 對象類型有繼承關係即多態時,就必須寫了
代碼以下:
package com.atguigu.chapter06.ClassAndObject
object Demo01 { def main(args: Array[String]): Unit = { //在開發中,咱們會從數據庫中獲取對個對象(封裝) //咱們一般不會去改變e對象自己 e = null //一般是對e對象進行查看,或者修改 val e = new Employee() e.sal += 1.0 //e = null 在開發中很少,所以咱們建立對象時,通常來講是val println("e.sal=" + e.sal)
/* scala在聲明對象變量時,能夠根據建立對象的類型自動推斷,因此類型聲明能夠省略, 但當類型和後面new 對象類型有繼承關係即多態時,就必須寫了 */ val e2: A = new Employee() println(e2) // e2 } }
class A { } //Employee類 class Employee extends A{ var id: Int = 10 var name: String = "tom" var sal: Double = 10000.0
override def toString: String = { return "id=" + id + "name=" + name + "sal=" + sal } }
|
6.1.7 類和對象的內存分配機制
6.1.8 方法
Scala中的方法其實就是函數,只不過通常將對象中的函數稱之爲方法。聲明規則請參考函數式編程中的函數聲明。
def 方法名(參數列表) [:返回值類型] = {
方法體
}
給Cat類添加cal方法,能夠計算兩個數的和
6.1.9 課堂練習題
1) 編寫類(MethodExec),編程一個方法,方法不須要參數,在方法中打印一個
10*8 的矩形,在main方法中調用該方法。
2) 修改上一個程序,編寫一個方法中,方法不須要參數,計算該矩形的面積,並將其做爲方法返回值。在main方法中調用該方法,接收返回的面積值並打印(結果保留小數點2位)。
第一題和第二題的代碼:
課後的練習
6.2 類與對象應用實例
6.2.1 小狗案例
1) 編寫一個Dog類,包含name(String)、age(int)、weight(double)屬性
2) 類中聲明一個say方法,返回String類型,方法返回信息中包含全部屬性值。
3) 在另外一個TestDog Object中的main方法中,建立Dog對象,並訪問say方法和全部屬性,將調用結果打印輸出
4) 代碼:
6.3 構造器
6.3.1 看一個需求
咱們來看一個需求:前面咱們在建立Person的對象時,是先把一個對象建立好後,再給他的年齡和姓名屬性賦值,若是如今我要求,在建立人類的對象時,就直接指定這個對象的年齡和姓名,該怎麼作? 這時就可使用構造方法/構造器。
6.3.2 回顧-Java構造器基本語法
[修飾符] 方法名(參數列表){
構造方法體
}
6.3.3 回顧-Java構造器的特色
1) 在Java中一個類能夠定義多個不一樣的構造方法,構造方法重載
2) 若是程序員沒有定義構造方法,系統會自動給類生成一個默認無參構造方法(也叫默認構造器),好比 Person (){}
3) 一旦定義了本身的構造方法,默認的構造方法就覆蓋了,就不能再使用默認的無參構造方法,除非顯示的定義一下,即: Person(){};
4) 案例
6.3.4 Scala構造器的介紹
和Java同樣,Scala構造對象也須要調用構造方法,而且能夠有任意多個構造方法。
Scala類的構造器包括: 主構造器 和 輔助構造器
6.3.5 Scala構造器的基本語法
class 類名(形參列表) { // 主構造器
// 類體
def this(形參列表) { // 輔助構造器
}
def this(形參列表) { //輔助構造器能夠有多個...
}
}
。
6.3.6 快速入門
建立Person對象的同時初始化對象的age屬性值和name屬性值
6.3.7 Scala構造器注意事項和細節
1) Scala構造器做用是完成對新對象的初始化,構造器沒有返回值。
2) 主構造器的聲明直接放置於類名以後 [反編譯]
3) 主構造器會執行類定義中的全部語句,這裏能夠體會到Scala的函數式編程和麪向對象編程融合在一塊兒,即:構造器也是方法(函數),傳遞參數和使用方法和前面的函數部份內容沒有區別【案例演示+反編譯]
對應的反編譯的文件
4) 若是主構造器無參數,小括號可省略,構建對象時調用的構造方法的小括號也能夠省略
5) 輔助構造器名稱爲this(這個和Java是不同的),多個輔助構造器經過不一樣參數列表進行區分, 在底層就是java的構造器重載.
在對應的反編譯的.class 對應class Person2
6) 若是想讓主構造器變成私有的,能夠在()以前加上private,這樣用戶只能經過輔助構造器來構造對象了.
說明:由於Person3的主構造器是私有,所以就須要使用輔助構造器來建立對象。
7) 輔助構造器的聲明不能和主構造器的聲明一致,會發生錯誤
6.4 屬性高級
前面咱們講過屬性了,這裏咱們再對屬性的內容作一個增強.
6.4.1 構造器參數
1) Scala類的主構造器函數的形參未用任何修飾符修飾,那麼這個參數是局部變量。
2) 若是參數使用val關鍵字聲明,那麼Scala會將參數做爲類的私有的只讀屬性使用 【案例+反編譯】
3) 若是參數使用var關鍵字聲明,那麼那麼Scala會將參數做爲類的成員屬性使用,並會提供屬性對應的xxx()[相似getter]/xxx_$eq()[相似setter]方法,即這時的成員屬性是私有的,可是可讀寫。【案例+反編譯】
4) 代碼
對應的反編譯的.class文件
6.4.2 Bean屬性
JavaBeans規範定義了Java的屬性是像getXxx()和setXxx()的方法。許多Java工具(框架)都依賴這個命名習慣。爲了Java的互操做性。將Scala字段加@BeanProperty時,這樣會自動生成規範的 setXxx/getXxx 方法。這時可使用 對象.setXxx() 和 對象.getXxx() 來調用屬性。
給某個屬性加入@BeanPropetry註解後,會生成getXXX和setXXX的方法
而且對原來底層自動生成相似xxx(),xxx_$eq()方法,沒有衝突,兩者能夠共存。
反編譯的.class文件
6.5 對象建立的流程分析
6.5.1 看一個案例
class Person {
var age: Int = 90
var name: String = _
def this(n: String, a: Int) {
this()
this.name = n
this.age = a
}
}
var p : Person = new Person("小倩",20)
6.5.2 流程分析(面試題)
1) 加載類信息(屬性信息,方法信息)
2) 在堆中,給對象開闢空間
3) 調用主構造器對屬性進行初始化
4) 使用輔助構造器對屬性進行初始化
5) 把對象空間的地址,返回給p引用
第 7 章 面向對象編程(中級)
7.1 包
7.1.1 看一個應用場景
如今有兩個程序員共同開發一個項目,程序員xiaoming但願定義一個類取名 Dog ,程序員xiaoqiang也想定義一個類也叫 Dog。兩個程序員爲此還吵了起來,怎麼辦?
7.1.2 回顧-Java包的三大做用
1) 區分相同名字的類
2) 當類不少時,能夠很好的管理類
3) 控制訪問範圍
7.1.3 回顧-Java打包命令
打包基本語法
package com.atguigu;
7.1.4 打包的本質分析
實際上就是建立不一樣的文件夾來保存類文件,畫出示意圖。
7.1.5 快速入門
使用打包技術來解決上面的問題,不一樣包下Dog類
7.1.6 回顧-Java如何引入包
語法: import 包;
好比 import java.awt.*;
咱們引入一個包的主要目的是要使用該包下的類
好比 import java.util.Scanner; 就只是引入一個類Scanner。
7.1.7 回顧-Java包的特色
java中包名和源碼所在的系統文件目錄結構要一致,並
且編譯後的字節碼文件路徑也和包名保持一致。[如圖]
7.1.8 Scala包的基本介紹
和Java同樣,Scala中管理項目可使用包,但Scala中的包的功能更增強大,使用也相對複雜些,下面咱們學習Scala包的使用和注意事項。
7.1.9 Scala包快速入門
使用打包技術來解決上面的問題,不一樣包下Dog類
7.1.10 Scala包的特色概述
7.1.11 Scala包的命名
只能包含數字、字母、下劃線、小圓點.,但不能用數字開頭, 也不要使用關鍵字。
demo.class.exec1 //對嗎 錯誤,由於 class 關鍵字
demo.12a // 對嗎,錯誤
通常是小寫字母+小圓點通常是
com.公司名.項目名.業務模塊名
好比:com.atguigu.oa.model com.atguigu.oa.controller
com.sina.edu.user
com.sohu.bank.order
7.1.12 Scala會自動引入的經常使用包
7.1.13 Scala包注意事項和使用細節
1) scala進行package 打包時,能夠有以下形式
2) 包也能夠像嵌套類那樣嵌套使用(包中有包), 這個在前面的第三種打包方式已經講過了,在使用第三種方式時的好處是:程序員能夠在同一個文件中,將類(class / object)、trait 建立在不一樣的包中,這樣就很是靈活了。[案例+反編譯]
3) 做用域原則:能夠直接向上訪問。即: Scala中子包中直接訪問父包中的內容, 大括號體現做用域。(提示:Java中子包使用父包的類,須要import)。在子包和父包 類重名時,默認採用就近原則,若是但願指定使用某個類,則帶上包名便可
package com.atguigu { class A01 { //這時,編譯器,就會在com.atguigu包下生成A01.class
} class Cat{ //這時,編譯器,就會在com.atguigu包下生成Cat.class
} package scala{ class A01 { ////這時,編譯器,就會在com.atguigu.sacla包下生成A01.class
} class Cat {////這時,編譯器,就會在com.atguigu.sacla包下生成Cat.class
} object Test01{ //這時,編譯器,就會在com.atguigu.sacla包下生成Test01.class Test01$.class def main(args: Array[String]): Unit = { println("ok~~")
//建立一個Cat對象 //說明 //1. Scala中子包中直接訪問父包中的內容 //2. 在子包和父包 類重名時,默認採用就近原則 //3. 若是但願指定使用某個類,則帶上包全名便可 val cat = new Cat() println("cat=" + cat) //使用的是com.atguigu.scala.Cat[使用就近原則] val cat2 = new com.atguigu.Cat()//使用的是com.atguigu.Cat[指定原則] println("cat2" + cat2)
} } } } |
4) 父包要訪問子包的內容時,須要import對應的類等
5) 能夠在同一個.scala文件中,聲明多個並列的package(建議嵌套的pakage不要超過3層)
6) 包名能夠相對也能夠絕對,好比,訪問BeanProperty的絕對路徑是:
_root_. scala.beans.BeanProperty ,在通常狀況下:咱們使用相對路徑來引入包,只有當包名衝突時,使用絕對路徑來處理
7.1.14 包對象
基本介紹:包能夠包含類、對象和特質trait,但不能包含函數或變量的定義。這是Java虛擬機的侷限。爲了彌補這一點不足,scala提供了包對象的概念來解決這個問題
7.1.15 包對象的應用案例
7.1.16 包對象的注意事項
7.2 包的可見性
7.2.1 Scala中包的可見性介紹:
在Java中,訪問權限分爲: public,private,protected和默認。在Scala中,你能夠經過相似的修飾符達到一樣的效果。可是使用上有區別。
7.2.2 Scala中包的可見性和訪問修飾符的使用
1) 當屬性訪問權限爲默認時,從底層看屬性是private的,可是由於提供了xxx_$eq()[相似setter]/xxx()[相似getter] 方法,所以從使用效果看是任何地方均可以訪問)
2) 當方法訪問權限爲默認時,默認爲public訪問權限
3) private爲私有權限,只在類的內部和伴生對象中可用 【案例演示】
4) protected爲受保護權限,scala中受保護權限比Java中更嚴格,只能子類訪問,同包沒法訪問
5) 在scala中沒有public關鍵字,即不能用public顯式的修飾屬性和方法。【案演】
6) 包訪問權限(表示屬性有了限制。同時增長了包的訪問權限),這點和Java不同,體現出Scala包使用的靈活性。
7.3 包的引入
7.3.1 Scala引入包的細節和注意事項
1) 在Scala中,import語句能夠出如今任何地方,並不只限於文件頂部,import語句的做用一直延伸到包含該語句的塊末尾。這種語法的好處是:在須要時在引入包,縮小import 包的做用範圍,提升效率。
2) Java中若是想要導入包中全部的類,能夠經過通配符*,Scala中採用下 _ [案例演示]
3) 若是不想要某個包中所有的類,而是其中的幾個類,能夠採用選取器(大括號)
4) 若是引入的多個包中含有相同的類,那麼能夠將不須要的類進行重命名進行區分,這個就是重命名
5) 若是某個衝突的類根本就不會用到,那麼這個類能夠直接隱藏掉
import java.util.{ HashMap=>_, _} //
7.4 面向對象編程方法-抽象
7.4.1 如何理解抽象
咱們在前面去定義一個類時候,實際上就是把一類事物的共有的屬性和行爲提取出來,造成一個物理模型(模板)。這種研究問題的方法稱爲抽象。[見後面ppt]
package com.atguigu.chapter06.abstractt
object AccountDemo01 { def main(args: Array[String]): Unit = { //測試一下咱們抽象的Account是否ok val myAccount = new Account("gh111111",200.0,123456) //查詢 myAccount.query(123456) //取款 myAccount.withdraw(123456, 201) myAccount.query(123456)
} }
/* 無論是哪一種帳號, 是誰的帳號 屬性: 帳號,餘額,密碼 方法 存款(depostie) 取款(withdraw) 查詢(query)
*/ class Account(InAccountNO:String,money:Double,inPwd:Int) { val accountNo:String = InAccountNO var banlance:Double = money var pwd:Int = inPwd
//查詢 def query(pwd:Int): Unit = { if (pwd != this.pwd) { println("密碼錯誤") return } println(this.accountNo + " 餘額是:" + this.banlance) }
//withdraw取款 def withdraw(pwd:Int, money:Int): Unit = { //判斷 if (pwd != this.pwd) { println("密碼錯誤") return } if (money > this.banlance) { println("餘額不足") return } this.banlance -= money println("取款成功" + this.accountNo + " 取出來 " + money + " 餘額有:" + this.banlance) }
}
|
7.5 面向對象編程三大特徵
7.5.1 基本介紹
面向對象編程有三大特徵:封裝、繼承和多態。下面咱們一一爲同窗們進行詳細的講解。
7.5.2 封裝介紹
封裝(encapsulation)就是把抽象出的數據和對數據的操做封裝在一塊兒,數據被保護在內部,程序的其它部分只有經過被受權的操做(成員方法),才能對數據進行操做
7.5.3 封裝的理解和好處
1) 隱藏實現細節
2) 提能夠對數據進行驗證,保證安全合理
7.5.4 如何體現封裝
1) 對類中的屬性進行封裝
2) 經過成員方法,包實現封裝
7.5.5 封裝的實現步驟
1) 將屬性進行私有化
2) 提供一個公共的set方法,用於對屬性判斷並賦值
def setXxx(參數名 : 類型) : Unit = {
//加入數據驗證的業務邏輯
屬性 = 參數名
}
3) 提供一個公共的get方法,用於獲取屬性的值
def getXxx() [: 返回類型] = {
return 屬性
}
7.5.6 快速入門案例
那麼在Scala中如何實現這種相似的控制呢?
請你們看一個小程序(TestEncap.scala),不能隨便查看人的年齡,工資等隱私,並對輸入的年齡進行合理的驗證[要求1-120之間]。
7.5.7 封裝的課堂練習題
7.5.8 Scala封裝的注意事項和細節
7.6 面向對象編程-繼承
7.6.1 Java繼承的簡單回顧
class 子類名 extends 父類名 { 類體 }
子類繼承父類的屬性和方法
7.6.2 繼承基本介紹和示意圖
繼承能夠解決代碼複用,讓咱們的編程更加靠近人類思惟.當多個類存在相同的屬性(變量)和方法時,能夠從這些類中抽象出父類(好比Student),在父類中定義這些相同的屬性和方法,全部的子類不須要從新定義這些屬性和方法,只須要經過extends語句來聲明繼承父類便可。
和Java同樣,Scala也支持類的單繼承。
畫出繼承的示意圖
7.6.3 Scala繼承的基本語法
class 子類名 extends 父類名 { 類體 }
7.6.4 Scala繼承快速入門
編寫一個Student 繼承 Person的案例,體驗一下Scala繼承的特色
package com.atguigu.chapter06.extend
object Extends01 { def main(args: Array[String]): Unit = { //測試 val stu1 = new Student stu1.name = "tom" stu1.age = 20 stu1.showInfo() stu1.studying()
} }
class Person { //屬性name 和 age,默認 var name : String = _ var age : Int = _ //方法 def showInfo(): Unit = { println("學生信息以下:") println("名字:" + this.name) } }
//extends關鍵字,繼承了Person class Student extends Person { //將Student特有方法寫在Student類 def studying(): Unit = { println(this.name + "學習 scala中....") } } |
7.6.5 Scala繼承給編程帶來的便利
1) 代碼的複用性提升了
2) 代碼的擴展性和維護性提升了【面試官問?】
7.6.6 子類繼承了什麼,怎麼繼承了?
子類繼承了全部的屬性,只是私有的屬性不能直接訪問,須要經過公共的方法去訪問【debug代碼驗證能夠看到】
代碼:
對應的反編譯的.class 文件
7.6.7 重寫方法
說明: scala明確規定,重寫一個非抽象方法須要用override修飾符,調用超類的方法使用super關鍵字 【案例演示+反編譯】
說明
1) 當上面的代碼被反編譯後,咱們發現override 關鍵字也去掉,即和java是同樣.
2) super在反編譯後,和java也同樣。
7.6.8 Scala中類型檢查和轉換
1) 要測試某個對象是否屬於某個給定的類,能夠用isInstanceOf方法。用asInstanceOf方法將引用轉換爲子類的引用。classOf獲取對象的類名。
2) classOf[String]就如同Java的 String.class 。
3) obj.isInstanceOf[T]就如同Java的obj instanceof T 判斷obj是否是T類型。
4) obj.asInstanceOf[T]就如同Java的(T)obj 將obj強轉成T類型。
package com.atguigu.chapter06.extend
object TypeConvertExer { def main(args: Array[String]): Unit = { //建立對象 val stu = new Stu val worker = new Worker test(stu) //stuid=.. test(worker)//workerId=
} def test(p: Person04): Unit = { //若是傳入是Student實例,則調用sayOk //若是傳入是Worker實例,則調用sayHello //進行p.asInstanceOf[T]轉換時,要求,p 的引用自己就是指向T類型的引用 if (p.isInstanceOf[Stu]) { //轉換 p.asInstanceOf[Stu].sayOk() } else if (p.isInstanceOf[Worker]) { p.asInstanceOf[Worker].sayHello() } else { println("轉換錯誤") } } }
class Person04 { var name : String = "tom" def printName() { println("Person printName() " + name) } }
class Stu extends Person04 { var stuId:Int = 100 def sayOk(): Unit = { println("stuid=" + this.stuId) } }
class Worker extends Person04 { var workerId:Int = 200 def sayHello(): Unit = { println("workerId=" + this.workerId) } }
|
7.6.9 Scala中超類的構造
說明:
從代碼能夠看出:在Java中,建立子類
對象時,子類的構造器老是去調用一個
父類的構造器(顯式或者隱式調用)
代碼:
package com.atguigu.chapter06.extend;
public class SuperConstruct { public static void main(String[] args) { //測試 //下面代碼執行的效果是: // A() // B() // A(String name)jack // B(String name)jack B02 b = new B02(); B02 b2 = new B02("jack"); } } //父類 A02 class A02 { //構造器無參. public A02() { System.out.println("A()"); } //構造器,有參 public A02(String name) { System.out.println("A(String name)" + name); } } //子類B02,繼承A02 class B02 extends A02{
public B02() { //這裏會隱式調用super(); 就是無參的父類構造器A02() super(); System.out.println("B()"); } public B02(String name) { super(name); System.out.println("B(String name)" + name); } }
|
1) 類有一個主構器和任意數量的輔助構造器,而每一個輔助構造器都必須先調用主構造器(也能夠是間接調用.),這點在前面咱們說過了。
上面的代碼說明
(1) 先去執行extends Person05() 的Person05()
(2) 在執行class Emp05 類中的 主構造器 Emp05()
(3) 再執行 Emp05的輔助構造器 this(name:String)
2) 只有主構造器能夠調用父類的構造器。輔助構造器不能直接調用父類的構造器。在Scala的構造器中,你不能調用super(params).
package com.atguigu.chapter06.extend
object ScalaSuperConstructExer1 { def main(args: Array[String]): Unit = { //建立一個學生對象 //分析下面的代碼是如何運行的 //1.Person06( pname : String ) name= jack //2.Student06( studentname : String ) sno = 20
val stu = new Student06("jack") stu.printName() //Student printName() name jack sno 20 //Person printName() jack } }
class Person06( pname : String ) { var name : String = pname def printName() { println("Person printName() " + name) } def this() { this("xx") } } class Emp06(empname : String) extends Person06(empname) { var empno : Int = 10 //這裏須要顯示的使用override override def printName() { println("Emp printName() " + name) super.printName() } }
class Student06( studentname : String ) extends Person06() { //xxx var sno : Int = 20 override def printName() { println("Student printName() " + name + "sno=" + sno) super.printName() } } |
class Student06( studentname : String ) extends Person06()
1) 當一個子類繼承了一個父類後,是上面語法.
2) extends Person06() 表示 當咱們構建一個子類對象,會調用父類的構造器 Person06(),要求咱們的父類,必須有一個對應的構造器,該構造器能夠是主構造器,也能夠是輔助構造器.
3) 父類的全部輔助構造器,仍然須要調用父類的主構造器
7.6.10 覆寫字段
在Scala中,子類改寫父類的字段,咱們成爲覆寫/重寫字段。覆寫字段需使用 override修飾。
package com.atguigu.chapter06.extend;
public class DaynDemo { public static void main(String[] args) { AA a = new BB(); //提出java的動態綁定機制 //1. 當調用對象方法的時候,該方法會和該對象的內存地址綁定 //2. 當調用對象屬性時,沒有動態綁定機制,哪裏聲明,那裏使用 //說明: //1. 若是沒有註銷BB的sum, a.sum() = 40 //2. 若是註銷BB的sum, a.sum() = 30 //3. 若是沒有註銷BB的sum1, a.sum1() = 30 //4. 若是註銷BB的sum1, a.sum1() = 20 System.out.println("a.sum=" + a.sum()); //40 =》 30 System.out.println("a.sum1=" + a.sum1());//30 =》 20 } }
class AA { public int i = 10; public int sum() { return getI() + 10; } public int sum1() { return i + 10; } public int getI() { return i; } }
class BB extends AA { public int i = 20; // public int sum() { // return i + 20; // } public int getI() { return i; } // public int sum1() { // return i + 10; // } } |
//提出java的動態綁定機制
//1. 當調用對象方法的時候,該方法會和該對象的內存地址綁定
//2. 當調用對象屬性時,沒有動態綁定機制,哪裏聲明,那裏使用
咱們看一個關於覆寫字段的案例。【案例演示+分析+反編譯】
1) def只能重寫另外一個def(即:方法只能重寫另外一個方法)
2) val只能重寫另外一個val 或 重寫不帶參數的def [案例+分析]
爲何編譯器不支持 val 去重寫 var 屬性,緣由是會形成數據設置和或者不一致.
b.age = 10 // b.age 調用的是父類的 public age_$eq()
println(b.age) //b.age 調用的子類的public age()
子類的val 屬性,能夠去重寫 父類不帶參數的def。
3) var只能重寫另外一個抽象的var屬性
案例演示:
1) 一個屬性沒有初始化,那麼這個屬性就是抽象屬
2) 抽象屬性在編譯成字節碼文件時,屬性並不會聲明,可是會自動生成抽象方法,因此類必須聲明爲抽象類
3) 若是是覆寫一個父類的抽象屬性,那麼override 關鍵字可省略 [緣由:父類的抽象屬性,生成的是抽象方法,所以就不涉及到方法重寫的概念,所以override可省略]
7.6.11 抽象類
在Scala中,經過abstract關鍵字標記不能被實例化的類。方法不用標記abstract,只要省掉方法體便可。抽象類能夠擁有抽象字段,抽象字段就是沒有初始值的字段
7.6.12 Scala抽象類使用的注意事項和細節討論
1) 抽象類不能被實例
2) 抽象類不必定要包含abstract方法。也就是說,抽象類能夠沒有abstract方法
3) 一旦類包含了抽象方法或者抽象屬性,則這個類必須聲明爲abstract
4) 抽象方法不能有主體,不容許使用abstract修飾。
5) 若是一個類繼承了抽象類,則它必須實現抽象類的全部抽象方法和抽象屬性,除非它本身也聲明爲abstract類。【案例演示+反編譯】
6) 抽象方法和抽象屬性不能使用private、final 來修飾,由於這些關鍵字都是和重寫/實現相違背的。
7) 子類重寫抽象方法不須要override,寫上也不會錯.
7.6.13 匿名子類
Java同樣,能夠經過包含帶有定義或重寫的代碼塊的方式建立一個匿名的子類
7.6.14 課後練習題
第 8 章
面向對象編程-高級
8.1 靜態屬性和方法
8.1.1 靜態屬性-提出問題
提出問題的主要目的就是讓你們思考解決之道,從而引出我要講的知識點.
說:有一羣小孩在玩堆雪人,不時有新的小孩加入,請問如何知道如今共有多少人在玩?請使用面向對象的思想,編寫程序解決
基本介紹
8.1.2 回顧下Java的靜態概念
public static 返回值類型 方法名(參數列表) {方法體}
說明: Java中靜態方法並非經過對象調用的,而是經過類對象調用的,因此靜態操做並非面向對象的。
8.1.3 Scala中靜態的概念-伴生對象
說明:Scala語言是徹底面向對象(萬物皆對象)的語言,因此並無靜態的操做(即在Scala中沒有靜態的概念)。可是爲了可以和Java語言交互(由於Java中有靜態概念),就產生了一種特殊的對象來模擬類對象,咱們稱之爲類的伴生對象。這個類的全部靜態內容均可以放置在它的伴生對象中聲明和調用
8.1.4 伴生對象的快速入門
代碼的說明
1) println(ScalaPerson.sex) //這裏底層是 ScalaPerson$.Module$.sex()
2) 特色
class ScalaPerson { //生成 ScalaPerson類,會有對 object ScalaPerson 的屬性或方法操做
var name : String = _
}
8.1.5 伴生對象的小結
8.1.6 伴生對象解決小孩遊戲問題
若是,設計一個var total Int表示總人數,咱們在建立一個小孩時,就把total加1,而且 total是全部對象共享的就ok了!,咱們使用伴生對象來解決
畫一個小圖給你們理解。
package com.atguigu.chapter08.objectt
object ChildGame { def main(args: Array[String]): Unit = { val child1 = new Child("白骨精") val child2 = new Child("蜘蛛精") val child3 = new Child("犀牛精") Child.joinGame(child1) //Child$.Module$ 這個是一個靜態變量 Child.joinGame(child2) Child.joinGame(child3) //顯示人數 Child.showNum() } }
class Child(cName: String) { var name: String = cName }
object Child { //靜態的屬性 var totalNum: Int = 0 //加入遊戲的方法 def joinGame(c: Child): Unit = { println(c.name + " 加入到遊戲中...") totalNum += 1 } //顯示當前有多少小孩的方法 def showNum(): Unit = { printf("當前有%d個小孩完遊戲\n", totalNum) } }
|
8.1.7 apply方法的補充
8.2 單例對象
8.2.1 什麼是單例對象
單例對象是指:使用單例設計模式保證在整個的軟件系統中,某個類只能存在一個對象實例
8.2.2 回顧-Java單例對象
在Java中,建立單例對象分爲餓漢式和懶漢式,咱們看看是如何實現的
步驟以下:
1) 構造器私有化
2) 類的內部建立對象
3) 向外暴露一個靜態的公共方法
4) 代碼實現
package com.atguigu.chapter08.single;
public class JavaSingle { public static void main(String[] args) { //餓漢式 Single s1 = Single.getInstance();//獲得一個Single對象 Single s2 = Single.getInstance();//獲得一個Single對象 System.out.println(s1 == s2); // true
//懶漢式
//對上面兩種方式的優化 System.out.println("----------------------------------"); Singleton ss1 = Singleton.getInstance(); Singleton ss2 = Singleton.getInstance(); System.out.println("ss1.hashcode" + ss1.hashCode()); System.out.println("ss2.hashcode" + ss2.hashCode());
} }
//缺點是 建立了,可是用,有資源浪費 //優勢:線程安全。 class Single{// 餓漢式 private Single(){} //私有化構造器 private static Single s = new Single(); public static Single getInstance(){ return s; } }
//優勢:在使用的時候,纔去建立,所以沒有資源的浪費。 //缺點:有線程安全問題 class Single2{// 懶漢式 private Single2(){} //私有化構造器 private static Single2 s = null; public static Single2 getInstance(){ if (s == null) { s = new Single2(); } return s; } }
//對上面的兩種方法進行優化,使用靜態內部類來優化 class Singleton { private Singleton() {} //私有化 // //靜態內部類 1.在使用到時,纔會加載 2.在加載時,不會中斷(線程安全) private static class SingletonInstance{ private static final Singleton INSTANCE = new Singleton(); } public static Singleton getInstance() { //對外提供的public靜態方法 return SingletonInstance.INSTANCE; } } |
8.2.3 Scala中單例對象
8.2.4 單例模式的面試題
8.3 接口
8.3.1 回顧Java接口
interface 接口名
class 實現類類名 implements 接口名1,接口2
1) 在Java中, 一個類能夠實現多個接口。
2) 在Java中,接口之間支持多繼承
3) 接口中屬性都是常量
4) 接口中的方法都是抽象的
8.3.2 Scala接口的介紹
從面向對象來看,接口並不屬於面向對象的範疇,Scala是純面向對象的語言,在Scala中,沒有接口。
Scala語言中,採用特質trait(特徵)來代替接口的概念,也就是說,多個類具備相同的特徵(特徵)時,就能夠將這個特質(特徵)獨立出來,採用關鍵字trait聲明。
8.4 特質(trait)
8.4.1 trait 的聲明
trait 特質名 {
trait體
}
1) trait 命名 通常首字母大寫.
Cloneable , Serializable
object T1 extends Serializable {
}
Serializable: 就是scala的一個特質。
8.4.2 Scala中trait 的使用
說明
1) 類和特質關係,使用的 繼承的關係。由於scala的特質,有傳統interface 特色,同時又抽象類特色。
2) 當一個類去繼承特質時,第一個鏈接詞是extends ,後面是with
3) 若是一個類在繼承特質和父類時,應當把父類寫在extends後。
8.4.3 特質的快速入門案例
package com.atguigu.chapter08.traitpart
object TraitDemo01 { def main(args: Array[String]): Unit = { println("ok~") val c = new C c.getConnect("root", "123456") var f = new F f.getConnect("admin", "11111") } }
//增長獲取數據庫鏈接功能(實現能夠不一樣) //(trait)
//編寫一個trait ,寫上鍊接數據庫的方法的規範 trait Trait01 { //抽象方法 def getConnect(user:String, pwd:String): Unit }
//1. 先把繼承關係寫出
class A {} class B extends A{} class C extends A with Trait01{ override def getConnect(user: String, pwd: String): Unit = { println("鏈接mysql數據庫...") } }
class D {} class E extends D {} class F extends D with Trait01{ override def getConnect(user: String, pwd: String): Unit = { println("鏈接oracle數據庫..") } }
|
1) 若是咱們建立了一個trait [Trait01] , 該trait只有抽象的方法,那麼在底層就只會生成一個interface , 文件Trait01.class
2) 繼承了trait的類,並行實現trait的抽象方法(這點和java同樣)
8.4.4 特質trait 的再說明
1) Scala提供了特質(trait),特質能夠同時擁有抽象方法和具體方法,一個類能夠實現/繼承多個特質。【案例演示+反編譯】
2) 特質中沒有實現的方法就是抽象方法。類經過extends繼承特質,經過with能夠繼承多個特質
3) 全部的java接口均可以當作Scala特質使用
8.4.5 帶有特質的對象,動態混入
1) 除了能夠在類聲明時繼承特質之外,還能夠在構建對象時混入特質,擴展目標類的功能【反編譯看動態混入本質】
代碼:
2) 此種方式也能夠應用於對抽象類功能進行擴展
3) 動態混入是Scala特有的方式(java沒有動態混入),可在不修改類聲明/定義的狀況下,擴展類的功能,很是的靈活,耦合性低 。
4) 動態混入能夠在不影響原有的繼承關係的基礎上,給指定的類擴展功能
5) 思考:若是抽象類中有沒有實現的方法,如何動態混入特質?
8.4.6 scala建立對象的四種形式
8.4.7 疊加特質
1) 構建對象的同時若是混入多個特質,稱之爲疊加特質,
2) 那麼特質聲明順序從左到右,方法執行順序從右到左。
1) 目的:分析疊加特質時,對象的構建順序,和執行方法的順序
2) 代碼
package com.atguigu.chapter08.traitpart
//疊加特質案例 object TraitDemo05 { def main(args: Array[String]): Unit = { val mySQL4 = new MySQL4 with File4 with DB4 //請思考 mySQL4 的構建順序 //1. 當構建一個混入對象時,構建順序和 聲明的順序一致(從左到右),機制和類的繼承一致.
//(1) Operate4.. //(2) Data4 //(3) DB4 //(4) File4
//看看當咱們執行混入對象的方法時,它的執行順序如何 //1. 執行方法時,是從右到左執行. println("mySQL4.insert(100) 執行順序.......") mySQL4.insert(100) //(1) 向文件 向數據庫 //(2) 向數據庫 向文件 //(3) 插入數據 = 100 插入數據 = 100
println("----------------------------------------") //val mySQL4_ = new MySQL4 with File4 with DB4 //(1) Operate4.. //(2) Data4 //(3) File4 //(4) DB4
} } class MySQL4 {} trait Operate4 { println("Operate4...") def insert(id : Int) } trait Data4 extends Operate4 { println("Data4") override def insert(id : Int): Unit = { println("插入數據 = " + id) } } trait DB4 extends Data4 { println("DB4") override def insert(id : Int): Unit = { println("向數據庫") super.insert(id) } } trait File4 extends Data4 { println("File4") override def insert(id : Int): Unit = { println("向文件") //Scala中特質中若是調用super,並非表示調用父特質的方法, // 而是向前面(左邊)繼續查找特質,若是找不到,纔會去父特質查找 super.insert(id) }} |
1) 當構建一個混入對象時,構建順序和 聲明的順序一致(從左到右),機制和類的繼承一致
2) 執行方法時,是從右到左執行(按特質)
3) Scala中特質的方法中若是調用super,並非表示調用父特質的方法,而是向前面(左邊)繼續查找特質,若是找不到,纔會去父特質查找
1) 特質聲明順序從左到右。
2) Scala在執行疊加對象的方法時,會首先從後面的特質(從右向左)開始執行
3) Scala中特質中若是調用super,並非表示調用父特質的方法,而是向前面(左邊)繼續查找特質,若是找不到,纔會去父特質查找
4) 若是想要調用具體特質的方法,能夠指定:super[特質].xxx(…).其中的泛型必須是該特質的直接超類類型
8.4.8 在特質中重寫抽象方法
package com.atguigu.chapter08.traitpart.traitabstractoverride02
object TraitAbstractOverride { def main(args: Array[String]): Unit = { //當咱們從新的特質的抽象方法(還調用super...) //考慮動態混入的順序問題 var mysql2 = new MySQL5 with DB5 mysql2.insert(100)
// 錯誤 var mysql3 = new MySQL5 with File5
// var mysql4 = new MySQL5 with File5 with DB5 // mysql4.insert(200)
//這裏混入時,就考慮的混入的順序和完整性. var mysql4 = new MySQL5 with DB5 with File5 mysql4.insert(200) } }
trait Operate5 { def insert(id: Int) //抽象方法 }
trait File5 extends Operate5 { //使用的是abstract override abstract override def insert(id: Int): Unit = { println("將數據保存到文件中..") super.insert(id) } }
trait DB5 extends Operate5 { def insert(id: Int): Unit = { println("將數據保存到數據庫中..") } } class MySQL5 {} |
8.4.9 看成富接口使用的特質
8.4.10 特質中的具體字段
8.4.11 特質構造順序
8.4.12 擴展類的特質
8.4.13 自身類型
自身類型:主要是爲了解決特質的循環依賴問題,同時能夠確保特質在不擴展某個類的狀況下,依然能夠作到限制混入該特質的 類的類型。
8.5 嵌套類
8.5.1 基本介紹
在Scala中,你幾乎能夠在任何語法結構中內嵌任何語法結構。如在類中能夠再定義一個類,這樣的類是嵌套類,其餘語法結構也是同樣。
嵌套類相似於Java中的內部類。
package com.atguigu.chapter08.innerclass
object InnerClass01 { def main(args: Array[String]): Unit = { //建立成員內部類對象 //1. 先建立ScalaOuterClasss實例 val outer01 = new ScalaOuterClass val outer02 = new ScalaOuterClass //2. 建立ScalaInnerClasss實例 //說明 //1. 在scala中 成員內部類的類型默認是和外部對象關聯 //2. 即 outer01.ScalaInnerClass類型 val inner01 = new outer01.ScalaInnerClass var inner02 = new outer02.ScalaInnerClass println(inner01 + " " + inner02)
//建立靜態內部類實例 val staticInner = new ScalaOuterClass.ScalaStaticInnerClass() println(staticInner)
} } class ScalaOuterClass { //外部類 class ScalaInnerClass { //成員內部類 } }
object ScalaOuterClass { //伴生對象 class ScalaStaticInnerClass { //靜態內部類 } }
|
請編寫程序,在內部類中訪問外部類的屬性。
代碼:
package com.atguigu.chapter08.innerclass
object InnerClass02 { def main(args: Array[String]): Unit = { //建立成員內部類對象 //1. 先建立ScalaOuterClasss實例 val outer01 = new ScalaOuterClass val outer02 = new ScalaOuterClass //2. 建立ScalaInnerClasss實例 //說明 //1. 在scala中 成員內部類的類型默認是和外部對象關聯 //2. 即 outer01.ScalaInnerClass類型 val inner01 = new outer01.ScalaInnerClass var inner02 = new outer02.ScalaInnerClass //println(inner01 + " " + inner02) inner01.info() //scott 1.2 }
}
class ScalaOuterClass { var name: String = "scott" private var sal: Double = 1.2
class ScalaInnerClass { //成員內部類 def info() = { // 訪問方式:外部類名.this.屬性名 // 怎麼理解 ScalaOuterClass.this 就至關因而 ScalaOuterClass 這個外部類的一個實例, // 而後經過 ScalaOuterClass.this 實例對象去訪問 name 屬性 // 只是這種寫法比較特別,學習java的同窗可能更容易理解 ScalaOuterClass.class 的寫法. println("name = " + ScalaOuterClass.this.name + " age =" + ScalaOuterClass.this.sal) } } }
|
請編寫程序,在內部類中訪問外部內的屬性。
8.5.2 類型投影
解決方式-使用類型投影
類型投影是指:在方法聲明上,若是使用 外部類#內部類 的方式,表示忽略內部類的對象關係,等同於Java中內部類的語法操做,咱們將這種方式稱之爲 類型投影(即:忽略對象的建立方式,只考慮類型)【案例演示】
8.6 數組的基本使用
package com.atguigu.chapter08.innerclass
object ArrayTest { def main(args: Array[String]): Unit = { //scala的數組的基本時候用 //不可變數組 //使用方式1 //建立 val arr01 = Array(10,20,30) //建立數組時,直接賦值 //遍歷 for (item <- arr01) { println(item) } //修改 arr01(0) = 90 for (item <- arr01) { println(item) }
//方式2 val arr02 = new Array[Int](10) //默認爲0 println("--------arr02--------") for (item <- arr02) { println(item) } arr02(9) = 90 for (item <- arr02) { println(item) }
} }
|
第 9 章 隱式轉換和隱式參數
9.1 隱式轉換
9.1.1 提出問題
9.1.2 隱式函數基本介紹
隱式轉換函數是以implicit關鍵字聲明的帶有單個參數的函數。這種函數將會自動應用,將值從一種類型轉換爲另外一種類型
9.1.3 隱式函數快速入門
9.1.4 隱式函數的底層工做原理
9.1.5 隱式轉換的注意事項和細節
1) 隱式轉換函數的函數名能夠是任意的,隱式轉換與函數名稱無關,只與函數簽名(函數參數類型和返回值類型)有關。
2) 隱式函數能夠有多個(即:隱式函數列表),可是需要保證在當前環境下,只有一個隱式函數能被識別
9.2 隱式轉換豐富類庫功能
9.2.1 基本介紹
若是須要爲一個類增長一個方法,能夠經過隱式轉換來實現。(動態增長功能)好比想爲MySQL類增長一個delete方法
9.2.2 分析解決方案
在當前程序中,若是想要給MySQL類增長功能是很是簡單的,可是在實際項目中,若是想要增長新的功能就會須要改變源代碼,這是很難接受的。並且違背了軟件開發的OCP開發原則 【open close princeple】
在這種狀況下,能夠經過隱式轉換函數給類動態添加功能。
9.2.3 快速入門案例
9.3 隱式值
9.3.1 基本介紹
隱式值也叫隱式變量,將某個形參變量標記爲implicit,因此編譯器會在方法省略隱式參數的狀況下去搜索做用域內的隱式值做爲缺省參數
9.3.2 應用案例
9.3.3 課堂測試題
9.3.4 課堂練習
package com.atguigu.chapter09.implicitpart
object ImplicitExer02 {
def main(args: Array[String]): Unit = { // 隱式變量(值) implicit val name: String = "Scala" implicit val name1: String = "World"
def hello(implicit content: String = "jack"): Unit = { println("Hello " + content) } //調用hello hello } } |
1) 隱式值的優先級高於默認值
2) 當匹配到多個隱式值就會報錯(匹配時,是安裝類型匹配)
9.4 隱式類
9.4.1 基本介紹
在scala2.10後提供了隱式類,可使用implicit聲明類,隱式類的很是強大,一樣能夠擴展類的功能,比前面使用隱式轉換豐富類庫功能更加的方便,在集合中隱式類會發揮重要的做用。
9.4.2 隱式類使用有以下幾個特色:
1) 其所帶的構造參數有且只能有一個
2) 隱式類必須被定義在「類」或「伴生對象」或「包對象」裏,即隱式類不能是 頂級的(top-level objects)。
3) 隱式類不能是case class(case class在後續介紹)
4) 做用域內不能有與之相同名稱的標示符
9.4.3 應用案例
9.5 隱式的轉換時機
1) 當方法中的參數的類型與目標類型不一致時
2) 當對象調用所在類中不存在的方法或成員時,編譯器會自動將對象進行隱式轉換(根據類型)
9.6 隱式解析機制
9.7 隱式轉換的前提
在進行隱式轉換時,須要遵照兩個基本的前提:
1) 不能存在二義性
2) 隱式操做不能嵌套 // [舉例:]如:隱式轉換函數
第 10 章
數據結構上-集合
10.1 數據結構的特色
10.1.1 scala集合基本介紹
1) Scala同時支持不可變集合和可變集合,不可變集合能夠安全的併發訪問
2) 兩個主要的包:
不可變集合:scala.collection.immutable
可變集合: scala.collection.mutable
3) Scala默認採用不可變集合,對於幾乎全部的集合類,Scala都同時提供了可變和不可變的版本
10.1.2 可變集合和不可變集合舉例
1) 不可變集合:scala不可變集合,就是這個集合自己不能變[內存地址不能變](相似java的數組,是不能夠動態增加的)
2) 可變集合:可變集合(ArrayList , 是能夠動態增加的) 就是這個集合的自己是能夠變的[內存地址可變],成爲一個新的集合.
3) 以java舉例說明
package com.atguigu.chapter10.collection;
import java.util.ArrayList; public class JavaCollection { public static void main(String[] args) {
//不可變集合相似java的數組 int[] nums = new int[3]; nums[2] = 11; //? //nums[3] = 90; //?
// String[] names = {"bj", "sh"}; // System.out.println(nums + " " + names); // // //可變集合舉例 ArrayList al = new ArrayList<String>(); al.add("zs"); al.add("zs2"); System.out.println(al + " " + al.hashCode()); //地址 al.add("zs3"); System.out.println(al + " " + al.hashCode()); //地址 } } |
10.2 不可變集合繼承層次一覽
1.Set、Map是Java中也有的集合
2.Seq是Java沒有的,咱們發現List歸屬到Seq了,所以這裏的List就和java不是同
一個概念了
3.咱們前面的for循環有一個 1 to 3 ,就是IndexedSeq 下的Vector
4.String也是屬於IndexeSeq
5.咱們發現經典的數據結構好比Queue 和 Stack被歸屬到LinerSeq
6.你們注意Scala中的Map體系有一個SortedMap,說明Scala的Map能夠支持
排序
7.IndexSeq 和 LinearSeq 的區別[IndexSeq是經過索引來查找和定位,
所以速度快,好比String就是一個索引集合,經過索引便可定位]
[LineaSeq 是線型的,即有頭尾的概念,這種數據結構通常是經過遍從來查找,
它的價值在於應用到一些具體的應用場景
10.3 Scala可變集合繼承關係一覽圖
10.4 數組-定長數組(聲明泛型)
10.4.1 第一種方式定義數組
這裏的數組等同於Java中的數組,中括號的類型就是數組的類型
val arr1 = new Array[Int](10)
//賦值,集合元素採用小括號訪問
arr1(1) = 7
package com.atguigu.chapter10.arraypart
object ArrayDemo01 { def main(args: Array[String]): Unit = { //說明 //1. new 是關鍵字,[Int] 是指定能夠存放的數據類型 //2. 若是但願存聽任意數據類型,則指定Any //3. (4) ,表示數組的大小,肯定後就不能夠變化 //4. 在底層 Array 對應的代碼是 /* int[] nums = new int[3]; nums[2] = 11; */ val arr01 = new Array[Int](4) println(arr01.length) // 4 arr01(3) = 10 //修改某個元素的值 //遍歷數組 for (i <- arr01) { println(i) } } } |
|
10.4.2 第二種方式定義數組
在定義數組時,直接賦值
//使用apply方法建立數組對象
val arr1 = Array(1, 2)
//第二種建立數組的方式apply var arr02 = Array(1, 3, "xxx") for (i <- arr02) { println(i) } |
10.5 數組-變長數組(聲明泛型)
10.5.1 基本使用和應用案例
package com.atguigu.chapter10.arraypart
import scala.collection.mutable.ArrayBuffer
object ArrayBuffer01 { def main(args: Array[String]): Unit = { //說明 //1. ArrayBuffer 須要引入 scala.collection.mutable.ArrayBuffer //2. ArrayBuffer[Any](3, 2, 5) 的 (3, 2, 5) 初始元素有三個 //3. ArrayBuffer是有序的集合!!!! //4. 增長元素使用的是 append方法(),支持可變參數。 val arr01 = ArrayBuffer[Any](3, 2, 5) //遍歷數組 for (i <- arr01) { println(i) } println(arr01.length) // 3 //println("arr01.hash=" + arr01.hashCode())
//增長了元素,使用的方法是 //def append(elems: A*) { appendAll(elems) } arr01.append(90.0,13) //println("arr01.hash=" + arr01.hashCode())
arr01(1) = 89 //修改第2個元素的值 println("--------------------------") for (i <- arr01) { println(i) } println(arr01.length) // 5 } }
|
10.5.2 定長數組與變長數組的轉換
arr1.toBuffer //定長數組轉可變數組
arr2.toArray //可變數組轉定長數組
1) arr2.toArray 返回結果纔是一個定長數組, arr2自己沒有變化
2) arr1.toBuffer返回結果纔是一個可變數組, arr1自己沒有變化
package com.atguigu.chapter10.arraypart
import scala.collection.mutable.ArrayBuffer
object Array22ArrayBuffer { def main(args: Array[String]): Unit = { //建立一個空的可變數組 val arr2 = ArrayBuffer[Int]() // 追加值 arr2.append(1, 2, 3) println(arr2) // 1,2,3
// ArrayBuffer ==> Array //說明 //1. arr2.toArray 返回的結果是一個新的定長數組集合 //2. arr2它沒有變化 val newArr = arr2.toArray
println(newArr) // // Array ===> ArrayBuffer //說明 //1. newArr.toBuffer 返回一個變長數組 newArr2 //2. newArr 沒有任何變化,依然是定長數組 val newArr2 = newArr.toBuffer newArr2.append(123) println(newArr2)
} }
|
10.6 數組-多維數組
10.6.1 多維數組的定義和使用
val arr = Array.ofDim[Double](3,4)
//說明:二維數組中有三個一維數組,每一個一維數組中有四個元素
package com.atguigu.chapter10.arraypart
object DimArray { def main(args: Array[String]): Unit = { //建立一個二維數組[3,4] //說明 //1. 建立了一個 二維數組, 有三個元素,每一個元素是,含有4個元素一維數組() //2. 在底層仍然是java的方式處理 // int[][] arr = (int[][])Array..MODULE$.ofDim(3, 4, ClassTag..MODULE$.Int()); // arr[1][2] = 88; val arr = Array.ofDim[Int](3, 4) arr(1)(2) = 88 //遍歷二維數組 for (i <- arr) { //i 就是一維數組 for (j <- i) { print(j + " ") } println() }
} }
|
10.6.2 關於特質的接受參數(多態的)補充
package com.atguigu.chapter10.arraypart
object TraitUse { def main(args: Array[String]): Unit = { //測試: val a01 = new A B.test(a01) // b ok.. } }
trait MyTrait01 {} //特質 //A類繼承MyTrait01 class A extends MyTrait01 {}
object B { //test方法,能夠接受一個繼承MyTrait01的類的實例(這點和java同樣,體現接口多態) def test(m: MyTrait01): Unit = { println("b ok..") } }
|
10.7 數組-Scala數組與Java數組的互轉
10.7.1 Scala數組轉Java數組(List)
在項目開發中,有時咱們須要將Scala數組轉成Java數組,看下面案例:
package com.atguigu.chapter10.arraypart
import scala.collection.mutable.ArrayBuffer
object ArraytoArrayList { def main(args: Array[String]): Unit = {
//建立了ArrayBuffer val arr = ArrayBuffer("1", "2", "3")
//下面的import 引入了咱們須要的隱式函數【這裏就是隱式函數的應用】 //implicit def bufferAsJavaList[A](b : scala.collection.mutable.Buffer[A]) : java.util.List[A] import scala.collection.JavaConversions.bufferAsJavaList
//這裏使用了咱們的隱式函數bufferAsJavaList完成兩個ArrayBuffer -> List 轉換 //返回的就是 List<String> val javaArr = new ProcessBuilder(arr)
//返回的是 List<String> val arrList = javaArr.command() println(arrList) //輸出 [1, 2, 3] } }
|
10.7.2 Java數組(List)轉Scala數組
在項目開發中,有時咱們須要將Java數組轉成Scala數組,看下面案例
//=============================================================================
//Java數組(List)轉Scala數組
import scala.collection.JavaConversions.asScalaBuffer import scala.collection.mutable println("---------------------Java數組(List)轉Scala數組--------------------------") // java.util.List ==> Buffer val scalaArr: mutable.Buffer[String] = arrList println(scalaArr) |
10.8 元組Tuple-元組的基本使用
10.8.1 基本介紹
元組也是能夠理解爲一個容器,能夠存放各類相同或不一樣類型的數據。
說的簡單點,就是將多個無關的數據封裝爲一個總體,稱爲元組
注意:元組中最大隻能有22個元素
10.8.2 元組的建立
package com.atguigu.chapter10.tuplepart
object TupleDemo01 { def main(args: Array[String]): Unit = { //說明 //1. 建立了一個元組 tuple1 相似 Tuple4 //2. 元組最多有 22個元素, Tuple1 ---->Tuple22 //3. 獲取元組的元素的方法 tuple._1 表示取出第一個元素,依次類推 //4. 下面的代碼的底層 Tuple4 tuple1 val tuple1 = (1, 2, 3, "hello") // 底層 Tuple4 tuple1
println(tuple1) println(tuple1._1 + " " + tuple1._2)
} } |
10.9 元組Tuple-元組數據的訪問
10.9.1 基本介紹
訪問元組中的數據,能夠採用順序號(_順序號),也能夠經過索引(productElement)訪問。
10.9.2 應用案例
/* override def productElement(n: Int) = n match { case 0 => _1 case 1 => _2 case 2 => _3 case 3 => _4 case _ => throw new IndexOutOfBoundsException(n.toString()) } */ println(tuple1.productElement(3)) //等價 tuple1._4,即第四個元素. |
10.10 元組Tuple-元組數據的遍歷
使用元組的迭代器進行遍歷.
println("----------------遍歷元組---------------------") //遍歷元組 for (item <- tuple1.productIterator) { println("item=" + item) } |
10.11 列表 List-建立List
10.11.1 基本介紹
Scala中的List 和Java List 不同,在Java中List是一個接口,真正存放數據是ArrayList,而Scala的List能夠直接存放數據,就是一個object,默認狀況下Scala的List是不可變的。
val List = scala.collection.immutable.List
object List extends SeqFactory[List]
10.11.2 創建List的應用案例
package com.atguigu.chapter10.listpart
object ListCreate { def main(args: Array[String]): Unit = {
//爲何能夠直接使用List ,和 Nil? //緣由是 在 package object scala 有聲明 /* val List = scala.collection.immutable.List val Nil = scala.collection.immutable.Nil */
val list1 = List(1,2,3) println("list1=" + list1) //空list的建立 val list2 = Nil println("list2=" + list2) //List()
} }
|
10.11.3 列表 List-訪問List元素
//訪問list的元素 //list(1) 表示的下標 是從0開始的. val e = list1(1) println("e=" + e) //2 |
10.11.4 列表 List-元素的追加
向列表中增長元素, 會返回新的列表/集合對象。注意:Scala中List元素的追加形式很是獨特,和Java不同。
var list1 = List(1, 2, 3, "abc") // :+運算符表示在列表的最後增長數據4 // 說明 :+ 是追加符號 //1. : 這邊是集合, + 這邊是元素. val list2 = list1 :+ 4 println(list1) //list1沒有變化 println(list2) //新的列表結果是 [1, 2, 3, "abc", 4] |
println("-------------------------------------") // +:運算符表示在列表的最前面增長數據40 // 說明 :+ 是追加符號 val list3 = 40 +: list1 println("list1=" + list1) //list1沒有變化 (1, 2, 3, "abc") println("list3=" + list3) //List(40, 1, 2, 3, "abc") |
10.11.5 方式3-在列表的最後增長數據
1) 符號::表示向集合中 新建集合添加元素。
2) 運算時,集合對象必定要放置在最右邊,
3) 運算規則,從右向左。
4) ::: 運算符是將集合中的每個元素加入到空集合中去[要求::: 左右兩邊都是集合]
package com.atguigu.chapter10.listpart
object ListAdd3 { def main(args: Array[String]): Unit = {
println("---------------案例演示------------------") //list1是一個列表 val list1 = List(1, 2, 3, "abc")
//步驟以下 //1. () 空集合 //2. ((1, 2, 3, "abc")) //3 (6, (1, 2, 3, "abc")) //4 (5,6, (1, 2, 3, "abc")) //5 (4,5,6, (1, 2, 3, "abc")) val list5 = 4 :: 5 :: 6 :: list1 :: Nil println("list5=" + list5)// 4,5,6, (1, 2, 3, "abc") //
//步驟 //1 (1, 2, 3, "abc") //2 (6, 1, 2, 3, "abc") //3 (5, 6, 1, 2, 3, "abc") //4 (4, 5, 6, 1, 2, 3, "abc") val list6 = 4 :: 5 :: 6 :: list1
println("list6=" + list6)
//步驟 //1. () //2. (1, 2, 3, "abc") //3. (6,1, 2, 3, "abc") //4. (5,6,1, 2, 3, "abc") //5. (4,5,6,1, 2, 3, "abc") val list7 = 4 :: 5 :: 6 :: list1 ::: Nil //4 :: 5 :: 6 :: list1 println("list7=" + list7) //案例1 + 說明
println("-----------課堂練習。。。----------------")
val list11 = List(1, 2, 3, "abc") val list55 = 4 :: 5 :: 6 :: list11 println(list55) //(4, 5, 6, 1, 2, 3, abc)
//錯誤! ::: 【6 ::: list12】 6是集合 // val list12 = List(1, 2, 3, "abc") // val list52 = 4 :: 5 :: 6 ::: list12 ::: Nil // println(list5)
val list1_ = List(1, 2, 3, "abc") val list5_ = 4 :: 5 :: list1_ ::: list1_ ::: Nil println("list5_=" + list5_) // (4,5,1, 2, 3, "abc",1, 2, 3, "abc")
} }
|
10.12 隊列 Queue-基本介紹
10.12.1 基本介紹
10.12.2 隊列的說明
1) 隊列是一個有序列表,在底層能夠用數組或是鏈表來實現。
2) 其輸入和輸出要遵循先入先出的原則。即:先存入隊列的數據,要先取出。後存入的要後取出
3) 在Scala中,由設計者直接給咱們提供隊列類型使用
10.12.3 應用案例
// 想q1中增長元素 20 // 說明 // 1. += 函數 def +=(elem: A): this.type = { appendElem(elem); this } // 2. q1 += 20 底層 q1.$plus$eq(20) // 3. 隊列中,能夠有重複數據 q1 += 20 //q1.$plus$eq(20) q1 += 20 //q1.$plus$eq(20) println(q1)
//說明 //1. 將List(2,4,6) 取出,而後加入到q1 q1 ++= List(2,4,6) println(q1) // (20,20,2,4,6) |
10.13 隊列 Queue-刪除隊列元素
//刪除隊列的元素 //1. 刪除的是隊列的第一個元素 //2. 隊列自己發生變化 q1.dequeue() println("q1=" + q1) |
10.14 隊列 Queue-給隊列添加元素
//使用方法添加元素 q1.enqueue(10,90,11) println("q1=" + q1) // (20,20,2,4,6,10,90,11) |
10.15 隊列 Queue-返回隊列的元素
10.15.1 返回隊列的第一個元素
//返回隊列的頭
val q2 = new mutable.Queue[Int] q2 ++= List(1,2,3) //說明 //執行 q2.head ,返回隊列頭元素,可是對隊列自己沒有影響 println("q2.head=" + q2.head) // 1 println("q2=" + q2) |
10.15.2 返回隊列最後一個元素
println(q1.last)
10.15.3 返回隊列的尾部
即:返回除了第一個之外剩餘的元素, 能夠級聯使用,這個在遞歸時使用較多。
//返回隊列尾部數據 // 說明 //1. q2.tail 返回的是一個隊列 [從q2的第一個元素後的全部元素] //2. q2自己沒有變化 //3. tail能夠級聯適應 val q3 = q2.tail println("q3=" + q3) //(2,3) |
10.16 關於上邊界和下邊界的知識點
10.17 映射 Map-基本介紹
10.17.1 Java中的Map回顧
HashMap 是一個散列表,它存儲的內容是鍵值對(key-value)映射,Java中的HashMap是無序的。
public class JavaMap { public static void main(String[] args) { HashMap<String,Integer> hm = new HashMap(); hm.put("no1", 100); hm.put("no2", 200); hm.put("no3", 300); hm.put("no4", 400);
System.out.println(hm); System.out.println(hm.get("no2"));
} }
|
10.18 Scala中的Map介紹
Scala中的Map 和Java相似,也是一個散列表,它存儲的內容也是鍵值對(key-value)映射,Scala中不可變的Map是有序的,可變的Map是無序的。
10.19 映射 Map-構建Map
10.19.1 方式1-構造不可變映射
Scala中的不可變Map是有序,構建Map中的元素底層是Tuple2類型
package com.atguigu.chapter10.mappart
object ScalaMap { def main(args: Array[String]): Unit = {
val map = Map("Alice" -> 10, "Bob" -> 20, "Kotlin" -> 30) println("map=" + map) //1. 取值, 知道key取值 println(map("Bob")) // 20 //2. 遍歷map for (v <- map) { println("v=" + v) println("v.key=" + v._1 + " v.value=" + v._2) } } }
|
1.從輸出的結果看到,輸出順序和聲明順序一致
2.構建Map集合中,集合中的元素實際上是Tuple2類型
3.默認狀況下(即沒有引入其它包的狀況下),Map是不可變map
4.爲何說Map中的元素是Tuple2 類型 [反編譯或看對應的apply]
10.19.2 方式2-構造可變映射
案例:
//構建可變的map //說明 //1. 可變的須要帶包 //2. 能夠是無序 val map2 = mutable.Map("Alice" -> 10, "Bob" -> 20, "Kotlin" -> 30) println("map2=" + map2) |
10.19.3 方式3-建立空的映射
val map3 = new scala.collection.mutable.HashMap[String, Int]
println(map3)
10.19.4 方式4-對偶元組
即建立包含鍵值對的二元組, 和第一種方式等價,只是形式上不一樣而已。
對偶元組 就是隻含有兩個數據的元組。
//以元組的方式構建map對象 val map3 = mutable.Map(("Alice" , 10), ("Bob" , 20), ("Kotlin" , 30)) println("map3=" + map3) |
10.20 映射 Map-取值
10.20.1 方式1-使用map(key)
val value1 = map1("Alice")
println(value1)
說明:
1) 若是key存在,則返回對應的值
2) 若是key不存在,則拋出異常
3) 在Java中,若是key不存在則返回null
10.20.2 方式2-使用contains方法檢查是否存在key
// 返回Boolean
// 1.若是key存在,則返回true
// 2.若是key不存在,則返回false
map4.contains("B")
//方式2,先判斷是否有key,而後作相應的處理 if (map3.contains("A")) { println("存在" + map3("A")) } else { println("key存在") } |
10.20.3 方式3-使用map.get(key).get取值
經過 映射.get(鍵) 這樣的調用返回一個Option對象,要麼是Some,要麼是None
/方式3: 是個get的方式來取值 var map4 = mutable.Map( ("A", 1), ("B", "北京"), ("C", 3) ) println(map4.get("A")) //Some val some1 = map4.get("A") for (item<-some1) { println("item=" + item) } println(map4.get("A").get) //獲得Some在取出 println("uuukey=" + map4.get("uuu"))// None |
1) map.get方法會將數據進行包裝
2) 若是 map.get(key) key存在返回some,若是key不存在,則返回None
3) 若是map.get(key).get key存在,返回key對應的值,不然,拋出異常 java.util.NoSuchElementException: None.get
10.20.4 方式4-使用map4.getOrElse()取值
getOrElse 方法 : def getOrElse[V1 >: V](key: K, default: => V1)
說明:
1) 若是key存在,返回key對應的值。
2) 若是key不存在,返回默認值。在java中底層有不少相似的操做
//方式4:使用getOrElse() val map5 = mutable.Map( ("A", 1), ("B", "北京"), ("C", 3) ) println(map5.getOrElse("A1","默認")) //1 |
10.20.5 選擇使用取值的方式建議
1) 若是你肯定key存在,則直接使用map(), 或者 get()便可
2) 若是不肯定key是否存在,可是隻是想獲得一個值,則使用getOrElse便可
3) 若是不肯定key是否存在,並且是當key不存在時,須要對應的業務邏輯則時候用constrait判斷..
10.21 映射 Map-對map修改、添加和刪除
10.21.1 更新map的元素
案例:
//更新map的元素 val map6 = mutable.Map( ("A", 1), ("B", "北京"), ("C", 3) ) //若是key存在,則修改 //若是key不存在,則添加 map6("A") = 20 println("map6=" + map6) |
1) map 是可變的,才能修改,不然報錯
2) 若是key存在:則修改對應的值,key不存在,等價於添加一個key-val
10.21.2 添加map元素
案例
//第1種添加,添加單對 key-val //說明 //1. 若是key不存在,則添加 //2. 若是key存在,則修改 val map7 = mutable.Map( ("A", 1), ("B", "北京"), ("C", 3) ) map7 += ( "D" -> 4 ) map7 += ( "B" -> 50 ) println("map7=" + map7) |
//也能夠添加多個key-val map7 += ("UU"->1, "FF"->3) |
10.21.3 刪除map元素
//刪除元素的操做 //說明 //1. 能夠刪除多個key //2. 若是key存在,則刪除,若是key不存在,就不會拋出異常 val map8 = mutable.Map( ("A", 1), ("B", "北京"), ("C", 3) ) map8 -= ("A", "BB") println("map8=" + map8) |
1) "A","B" 就是要刪除的key, 能夠寫多個.
2) 若是key存在,就刪除,若是key不存在,也不會報錯.
10.22 映射 Map-對map遍歷
//遍歷map val map9 = mutable.Map(("A", 1), ("B", "北京"), ("C", 3)) //方式1 for ((k, v) <- map9) { print("k=" + k + "v=" + v + "\t") } //方式2,只遍歷key for (k <- map9.keys) { print("k=" + k + "\t") } //方式3,只遍歷values for (v <- map9.values) { print("v=" + v + "\t") } //方式4,取出每一個元素(Tuple2) for (item <- map9) { println("item=" + item) // println("k=" + item._1 + "v=" + item._2) }
|
10.23 集 Set-基本介紹
集是不重複元素的結合。集不保留順序,默認是以哈希集實現
10.23.1 Java中Set的回顧
java中,HashSet是實現Set<E>接口的一個實體類,數據是以哈希表的形式存放的,裏面的不能包含重複數據。Set接口是一種一個不包含重複元素的 collection,HashSet中的數據也是沒有順序的
具體的代碼
package com.atguigu.chapter10.setpart; import java.util.*; public class JavaSet { public static void main(String[] args) { //說明 //1. 元素不能重複 //2. 沒有順序 HashSet hs = new HashSet<String>(); hs.add("jack"); hs.add("tom"); hs.add("jack"); hs.add("jack2"); System.out.println(hs);
} } |
10.23.2 Scala中Set的說明
默認狀況下,Scala 使用的是不可變集合,若是你想使用可變集合,須要引用 scala.collection.mutable.Set 包
10.24 集 Set-建立
10.24.1 可變set 和不可變set的建立
object ScalaSet { def main(args: Array[String]): Unit = {
//1. 建立一個Set // //默認是不可變集, 無序 val set01 = Set(1,2,4,"abc", 20, 13.4) println("set01=" + set01) //默認是可變集, 無序 val set02 = mutable.Set(1,2,4,"abc", 20, 67.8) println("set02=" + set02)
} } |
10.24.2 可變集合的元素添加
//可變Set的添加 //1. 若是添加的對象已經存在,則不會重複添加,也不會報錯 set02 += 11 set02 += 11 set02 += 11 //這種方式,就添加後,返回一個新的Set //set02.+(90) println("set02=" + set02) // 不可變的Set 不能執行 += , //set01 += 80
|
1) 1. 若是添加的對象已經存在,則不會重複添加,也不會報錯
2) set02.+(90)返回新的集合
10.24.3 可變集合的元素刪除
val set02 = mutable.Set(1,2,4,"abc")
set02 -= 2
set02.remove("abc")
println(set02)
說明:若是刪除的對象不存在,則不生效,也不會報錯
10.24.4 集Set的遍歷
val set02 = mutable.Set(1, 2, 4, "abc")
for(x <- set02) {
println(x)
}
10.25 集 Set-更多操做
第 11 章 數據結構下-集合操做
11.1 看一個實際需求
1) 要求:請將list(3,5,7) 中的全部元素都 * 2 ,將其結果放到一個新的集合中返回,即返回一個新的list(6,10,14), 請編寫程序實現.
2) 使用傳統的方法解決
11.2 集合元素的映射-map映射操做
11.2.1 講解了高階函數的基本使用
package com.atguigu.chapter11.mapoper
//高階函數基本使用
object HighOrderDef { def main(args: Array[String]): Unit = {
val res = test(sum, 2.0) println("res=" + res) // 4.0
//調用高階函數test2 test2(myPrint)
}
//test函數的說明 //1.test函數能夠接受一個函數,test函數就是高階函數 //2.f: Double => Double : f就是形參名,表示函數 ,Double:傳入的函數能夠形參(Double) // => 一個規定 Double 接受的函數的返回值. //3. n1: Double :普通的形參 def test(f: Double => Double, n1: Double) = { f(n1) //執行 }
def sum(d1: Double): Double = { d1 * 2 }
//再寫一個高階函數的使用 def test2(f: () => Unit): Unit = { f() }
def myPrint(): Unit = { println("hello,world!") } } |
11.2.2 使用map映射函數來解決
package com.atguigu.chapter11.mapoper
object MapOperDemo { def main(args: Array[String]): Unit = {
//使用傳統的方式 //1. 優勢 簡單,好理解 //2. 缺點: 不夠簡潔,高效,沒有使用函數式編程 // val list1 = List(3, 5, 7) // var list2 = List[Int]() // for (item <- list1) {//遍歷 // list2 = list2 :+ item * 2 // } // println(list2)
//使用map映射函數解決 val list1 = List(3, 5, 7) //對list1.map(mul) 解釋 //1. 將 list1集合元素遍歷,傳給mul,進行運算 2 * n //2. 將運算的結果放入到一個新的集合中,並返回 val list2 = list1.map(mul) println("list2=" + list2) // (6, 10, 14)) }
//寫成函數 def mul(n: Int): Int = { 2 * n } }
|
11.2.3 課堂練習
請將 val names = List("Alice", "Bob", "Nick") 中的全部單詞,所有轉成字母大寫,返回到一下新的List集合中.
代碼:
package com.atguigu.chapter11.mapoper
object MapExercise01 { def main(args: Array[String]): Unit = { val names = List("Alice", "Bob", "Nick") def upper(s:String): String = { s.toUpperCase } val names2 = names.map(upper) println("names=" + names2) // } }
|
11.2.4 flatmap映射:flat即壓扁,壓平,扁平化映射
flatmap:flat即壓扁,壓平,扁平化,效果就是將集合中的每一個元素的子元素映射到某個函數並返回新的集合。
object FlatMap { def main(args: Array[String]): Unit = {
val names = List("Alice", "Bob", "Nick") def upper( s : String ) : String = { s. toUpperCase } val names2 = names.flatMap(upper) println("names2=" + names2) //List(A, L, I, C, E, B, O, B, N, I, C, K) } } |
//注意:每一個字符串也是char集合
println(names.flatMap(upper)) //map 遍歷 【 "Alice", "Bob", "Nick" 】
//flatMap (A,l,i,c,e, ....) ==upper===>(A,L,I)
11.3 集合元素的過濾-filter
filter:將符合要求的數據(篩選)放置到新的集合中
將 val names = List("Alice", "Bob", "Nick") 集合中首字母爲'A'的篩選到新的集合。
package com.atguigu.chapter11.mapoper
object FilterMap { def main(args: Array[String]): Unit = { val names = List("Alice", "Bob", "Nick") //普通函數 //1. 若是s是以"A" 開頭的,我就返回true, 不然返回false def startA(s:String): Boolean = { s.startsWith("A") }
//2. 使用filter來對集合進行過濾操做 // 當咱們的names的每一個元素,會調用startA進行判斷,若是爲true,就放入到新集合 val names2 = names.filter(startA) println("names2=" + names2) // List("Alice")
} }
|
11.4 化簡
11.4.1 看一個需求:
val list = List(1, 20, 30, 4 ,5) , 求出list的和.
11.4.2 化簡:
package com.atguigu.chapter11.mapoper
object reduce { def main(args: Array[String]): Unit = { val list = List(1, 20, 30, 4, 5) //sum 返回兩個數的和 def sum(n1: Int, n2: Int): Int = { n1 + n2 } //分析執行流程.
//1, 20, 30, 4, 5 //1. (1,20) 30, 4,5 //2 (21 30), 4,5 //3. (51 , 4), 5 //4. 55 , 5 //5. 60
val res = list.reduceLeft(sum) println("res=" + res) // 60
//(1, (20, (30, (4, 5)))) val res2 = list.reduceRight(sum) println("res2=" + res2) // 60
} }
|
11.4.3 reduceLefft(_ - _)這個函數的執行邏輯如圖
reduceRight() 和 上面同樣,只是從右邊開始進行簡化.
11.4.4 課堂練習題
package com.atguigu.chapter11.mapoper
object ReduceExe { def main(args: Array[String]): Unit = { val list = List(1, 2, 3, 4 ,5) def minus( num1 : Int, num2 : Int ): Int = { num1 - num2 } println("r1=" + list.reduceLeft(minus)) // 輸出? -13 println("r2=" + list.reduceRight(minus)) //輸出? 3 println("r3=" + list.reduce(minus)) //輸出? 3 從左化簡
} }
|
package com.atguigu.chapter11.mapoper
object ReduceExe02 { def main(args: Array[String]): Unit = { /* 使用化簡的方法求出 List(3,4,2,7,5) 最小的值
*/ def minVal(n1:Int,n2:Int): Int = { if (n1 > n2) n2 else n1 } val list1 = List(3,4,2,7,5) println("最小值=" + list1.reduceLeft(minVal))
} }
|
11.5 摺疊
11.5.1 基本介紹
fold函數將上一步返回的值做爲函數的第一個參數繼續傳遞參與運算,直到list中的全部元素被遍歷。
11.5.2 應用案例
看下面代碼看看輸出什麼,並分析緣由.
package com.atguigu.chapter11.mapoper
object FoldDemo01 { def main(args: Array[String]): Unit = { val list = List(1, 2, 3, 4)
def minus(num1: Int, num2: Int): Int = { num1 - num2 } //執行流程分析(((5, 1), 2), 3, 4) println(list.foldLeft(5)(minus)) //-5 //執行流程分析:(1, 2, 3, 4) (3) println(list.foldRight(5)(minus)) //3
} }
|
11.5.3 foldLeft和foldRight 縮寫方法分別是:/:和:\
package com.atguigu.chapter11.mapoper
object FoldDemo02 { def main(args: Array[String]): Unit = {
val list4 = List(1, 9, 2, 8)
def minus(num1: Int, num2: Int): Int = { num1 - num2 } // /: 等價 foldLeft var i6 = (0 /: list4) (minus) // (-20) (1,9,2,8) println(i6) // 輸出?
// :\ 等價 foldRight i6 = (list4 :\ 10 )(minus) // (1,9,2,8) (-4) println(i6) // 輸出? // -4
} }
|
11.6 掃描
11.6.1 基本介紹
掃描,即對某個集合的全部元素作fold操做,可是會把產生的全部中間結果放置於一個集合中保存
11.6.2 案例演示
package com.atguigu.chapter11.mapoper
object ScanDemo { def main(args: Array[String]): Unit = { def minus( num1 : Int, num2 : Int ) : Int = { num1 - num2 } //5 (1,2,3,4,5) =>(5,4,2,-1,-5,-10) val i8 = (1 to 5).scanLeft(5)(minus) //Vector(5, 4, 2, -1, -5, -10) println(i8) def add( num1 : Int, num2 : Int ) : Int = { num1 + num2 } //5 (1,2,3,4,5) =>(5,6,8, 11,15,20) val i9 = (1 to 5).scanLeft(5)(add) //Vector(5, 6, 8, 11, 15, 20) println(i9)
} }
|
11.6.3 課堂練習
請寫出下面的運行結果
def test(n1:Int ,n2 :Int): Int = {
n1 * n2
}
val i10 = (1 to 3).scanLeft(3)(test)
println("i10=" + i10) // (3,3,6,18)
11.7 課堂練習1
val sentence = "AAAAAAAAAABBBBBBBBCCCCCDDDDDDD"
將sentence 中各個字符,經過foldLeft存放到 一個ArrayBuffer中
目的:理解flodLeft的用法.
package com.atguigu.chapter11.mapoper
import scala.collection.mutable.ArrayBuffer
object Exercise03 { def main(args: Array[String]): Unit = { val sentence = "AAAAAAAAAABBBBBBBBCCCCCDDDDDDD"
def putArry( arr : ArrayBuffer[Char], c : Char ): ArrayBuffer[Char] = { arr.append(c) arr } //建立val arr = ArrayBuffer[Char]() val arr = ArrayBuffer[Char]() println(sentence.foldLeft(arr)(putArry))
} }
|
11.8 課堂練習2
val sentence = "AAAAAAAAAABBBBBBBBCCCCCDDDDDDD"
使用映射集合,統計一句話中,各個字母出現的次數
提示:Map[Char, Int]()
看看java如何實現
使用scala的flodLeft摺疊方式實現.
課後完成思考:使用Scala的傳統方法來實現(相似Java)
package com.atguigu.chapter11.mapoper
object Exercise04 { def main(args: Array[String]): Unit = {
val sentence = "AAAAAGAAAAABBBBBBBBCCCCCDD" def charCount( map : Map[Char, Int], c : Char ): Map[Char, Int] = { map + (c -> (map.getOrElse(c, 0) + 1)) } val map2 = sentence.foldLeft(Map[Char, Int]())(charCount) println(map2)
} } |
11.9 擴展-拉鍊(合併)
11.9.1 基本介紹
在開發中,當咱們須要將兩個集合進行 對偶元組合並,可使用拉鍊。
11.9.2 應用實例
package com.atguigu.chapter11.zippart
object ZipDemo {
def main(args: Array[String]): Unit = {
val list1 = List(1, 2 ,3) val list2 = List(4, 5, 6) val list3 = list1.zip(list2) //((1,4), (2,5),(3,6))
println("list3=" + list3)
}
}
|
11.10 擴展-迭代器
11.10.1 基本說明
經過iterator方法從集合得到一個迭代器,經過while循環和for表達式對集合進行遍歷
11.10.2 應用案例
package com.atguigu.chapter11.iterator
object IteratorDemo { def main(args: Array[String]): Unit = { val iterator = List(1, 2, 3, 4, 5).iterator // println("--------遍歷方式1 -----------------") while (iterator.hasNext) { println(iterator.next()) } println("--------遍歷方式2 for -----------------") for(enum <- iterator) { println(enum) // }
} }
|
11.10.3 對iterator的使用的說明
1) iterator 的構建實際是 AbstractIterator 的一個匿名子類,該子類提供了
/*
def iterator: Iterator[A] = new AbstractIterator[A] {
var these = self
def hasNext: Boolean = !these.isEmpty
def next(): A =
*/
2) 該AbstractIterator 子類提供了 hasNext next 等方法.
3) 所以,咱們可使用 while的方式,使用hasNext next 方法變量
11.11 擴展-流 Stream
11.11.1 基本說明
stream是一個集合。這個集合,能夠用於存放無窮多個元素,可是這無窮個元素並不會一次性生產出來,而是須要用到多大的區間,就會動態的生產,末尾元素遵循lazy規則(即:要使用結果才進行計算的) 。
11.11.2 建立Stream對象
def numsForm(n: BigInt) : Stream[BigInt] = n #:: numsForm(n + 1)
val stream1 = numsForm(1)
package com.atguigu.chapter11.stream
object StreamDemo { def main(args: Array[String]): Unit = { //對下面的函數說明 //Stream 集合存放的數據類型是BigInt //numsForm 是自定義的一個函數,函數名是程序員指定的。 //建立的集合的第一個元素是 n , 後續元素生成的規則是 n + 1 //後續元素生成的規則是能夠程序員指定的 ,好比 numsForm( n * 4)...
def numsForm(n: BigInt) : Stream[BigInt] = n #:: numsForm(n + 1) val stream1 = numsForm(1) println("stream1=" + stream1) //我但願在取一個流集合數據 println(stream1.tail) //(2,?) println("stream1=" + stream1) // (1,2,?) println("stream1.head=" + stream1.head)
//println("stream1.last" + stream1.last) //死循環 } }
|
Stream 集合存放的數據類型是BigInt
numsForm 是自定義的一個函數,函數名是程序員指定的。
建立的集合的第一個元素是 n , 後續元素生成的規則是 n + 1
後續元素生成的規則是能夠程序員指定的 ,好比 numsForm( n * 4)...
11.12 擴展-視圖 View
11.12.1 基本介紹
Stream的懶加載特性,也能夠對其餘集合應用view方法來獲得相似的效果,具備以下特色:
view方法產出一個老是被懶執行的集合。
11.12.2 view不會緩存數據,每次都要從新計算
應用案例
請找到1-100 中,數字倒序排列 和它自己相同的全部數。
package com.atguigu.chapter11.view
object ViewDemo { def main(args: Array[String]): Unit = {
//函數 將一個數字,原封不動的返回 def multiple(num: Int): Int = { num }
//判斷一個數字,交換順序後,是否相等 def eq(i: Int): Boolean = { i.toString.equals(i.toString.reverse) }
//說明: 沒有使用view val viewSquares1 = (1 to 100) .map(multiple) .filter(eq) println(viewSquares1) //(1,2,3,。。。。11,22)
//說明: 沒有使用view val viewSquares2 = (1 to 100) .view .map(multiple) .filter(eq) println("viewSquares2=" + viewSquares2) //(SeqView)lazy for (item <- viewSquares2) { print(item + ",") }
// //for (x <- viewSquares1) {} // //使用view // val viewSquares2 = (1 to 100) // .view // .map(multiple) // .filter(eq) // println(viewSquares2)
} }
|
11.13 擴展-線程安全的集合
11.14 擴展-並行集合
11.14.1 基本介紹
Scala爲了充分使用多核CPU,提供了並行集合(有別於前面的串行集合),用於多核環境的並行計算。
package com.atguigu.chapter11.parallel
object ParallelDemo2 { def main(args: Array[String]): Unit = { val result1 = (0 to 100).map{case _ => Thread.currentThread.getName} val result2 = (0 to 100).par.map{case _ => Thread.currentThread.getName}.distinct println(result1) println(result2)
} }
|
11.15 擴展-操做符
11.15.1 基本介紹
這部份內容沒有必要刻意去理解和記憶,語法使用的多了,天然就會熟練的使用,該部份內容瞭解一下便可。
11.15.2 操做符擴展
1) 若是想在變量名、類名等定義中使用語法關鍵字(保留字),能夠配合反引號反引號 [案例演示]
val `val` = 42
2) 中置操做符:A 操做符 B 等同於 A.操做符(B)
val dog = new Dog dog.+(10) dog + 20
println(dog.age) // 40
class Dog { var age:Int = 10 def +(n:Int): Unit = { age += n } } |
3) 後置操做符:A操做符 等同於 A.操做符,若是操做符定義的時候不帶()則調用時不能加括號
class Operate {
//定義函數/方法的時候,省略的() def ++ = "123"
}
//後置操做符 val oper = new Operate println(oper++) // println(oper.++) |
4) 前置操做符,+、-、!、~等操做符A等同於A.unary_操做符 [案例演示]
val oper2 = new Operate2 !oper2 //
class Operate2 { // 聲明前置運算符 //unary :一元運算符 def unary_! = println("!!!!!!!") } |
5) 賦值操做符,A 操做符= B 等同於 A = A 操做符 B ,好比 A += B 等價 A = A + B
第 12 章
模式匹配
12.1 match
12.1.1 基本介紹
Scala中的模式匹配相似於Java中的switch語法,可是更增強大。
模式匹配語法中,採用match關鍵字聲明,每一個分支採用case關鍵字進行聲明,當須要匹配時,會從第一個case分支開始,若是匹配成功,那麼執行對應的邏輯代碼,若是匹配不成功,繼續執行下一個分支進行判斷。若是全部case都不匹配,那麼會執行case _ 分支,相似於Java中default語句
12.1.2 Java swtich應用案例
12.1.3 scala的match應用案例
package com.atguigu.chapter12.matchpart
object MatchDemo01 { def main(args: Array[String]): Unit = { /* 給你兩個數,根據運算符獲得相應的結果,使用match-case */ val n1 = 10 val n2 = 20 var res = 0 val operChar = '+' operChar match { case '+' => { res = n1 + n2 print("xx") } case '-' => res = n1 - n2 case '*' => res = n1 * n2 case '/' => res = n1 / n2 case _ => println("你的運算符有誤..") } println("res=" + res) // 30 } } |
12.1.4 match的細節和注意事項
1) 若是全部case都不匹配,那麼會執行case _ 分支,相似於Java中default語句
2) 若是全部case都不匹配,又沒有寫case _ 分支,那麼會拋出MatchError
3) 每一個case中,不用break語句,自動中斷case
4) 能夠在match中使用其它類型(任意類型),而不只僅是字符
5) => 等價於 java swtich 的 :
6) => 後面的代碼塊到下一個 case, 是做爲一個總體執行,可使用{} 擴起來,也能夠不擴。
12.2 守衛
12.2.1 基本介紹
若是想要表達匹配某個範圍的數據,就須要在模式匹配中增長條件守衛
12.2.2 應用案例
package com.atguigu.chapter12.matchpart
object MatchGuard { def main(args: Array[String]): Unit = { for (ch <- "+-3!") { //遍歷字符串 var sign = 0 var digit = 0 ch match { case '+' => sign = 1 case '-' => sign = -1 // 說明 // 1. 若是 ch.toString.equals("3") 爲真,則表示匹配成功 case _ if ch.toString.equals("3") => digit = 3 case _ if ch.toInt > 4 => println("大於4") case _ => sign = 2 } println(ch + " " + sign + " " + digit) }
} }
|
12.2.3 課堂思考題
12.3 模式中的變量
12.3.1 基本介紹
若是在case關鍵字後跟變量名,那麼match前表達式的值會賦給那個變量
12.3.2 案例
package com.atguigu.chapter12.matchpart
object MatchVar { def main(args: Array[String]): Unit = { val ch = 'B' //說明 //1. match的前面是一個表達式(即任何有值的便可) ch+1+f1() match { // ch 變量 case '+' => println("ok~") //說明,當代碼走到 case mychar ,就會將 ch賦給mychar case mychar => println("ok~~~~~" + mychar) case _ => println ("ok~~") }
} def f1(): Char = { 'D' } }
|
12.4 類型匹配
12.4.1 基本介紹
能夠匹配對象的任意類型,這樣作避免了使用isInstanceOf和asInstanceOf方法
12.4.2 應用案例
package com.atguigu.chapter12.matchpart
object MatchType { def main(args: Array[String]): Unit = { //下面的代碼的做用是,根據 a的值不一樣,返回不一樣數據類型 val a = 3 val obj = if(a == 1) 1 else if(a == 2) "2" else if(a == 3) BigInt(3) else if(a == 4) Map("aa" -> 1) else if(a == 5) Map(1 -> "aa") else if(a == 6) Array(1, 2, 3) else if(a == 7) Array("aa", 1) else if(a == 8) Array("aa")
//使用類型匹配來進行操做 val result = obj match {
case a : Int => a //說明 case b : Map[String, Int] => "對象是一個字符串-數字的Map集合" //1. 先將 obj 賦給 b , b的名稱就是一個普通變量名,程序員指定 //2. Map[String, Int] 類型 //3. 若是類型匹配成功,就會執行 => 後面的代碼 case b : Map[String, Int] => "對象是一個字符串-數字的Map集合" case c : Map[Int, String] => "對象是一個數字-字符串的Map集合" case d : Array[String] => "對象是一個字符串數組" case e : Array[Int] => "對象是一個數字數組" case f : BigInt => Int.MaxValue case _ => "啥也不是" }
println("res=" + result)
} }
|
12.4.3 類型匹配注意事項
1) Map[String, Int] 和Map[Int, String]是兩種不一樣的類型,其它類推。
2) 在進行類型匹配時,編譯器會預先檢測是否有可能的匹配,若是沒有則報錯.
val obj = 10
val result = obj match {
case a : Int => a
case b : Map[String, Int] => "Map集合"
case _ => "啥也不是"
}
3) 若是 case _ 出如今match 中間,則表示隱藏變量名,即不使用,而不是表示默認匹配
//使用類型匹配來進行操做 val result = obj match { //表示隱藏變量 case _ : Int => println("int被匹配") } |
12.5 匹配數組
12.5.1 基本介紹
1) Array(0) 匹配只有一個元素且爲0的數組。
2) Array(x,y) 匹配數組有兩個元素,並將兩個元素賦值爲x和y。固然能夠依次類推Array(x,y,z) 匹配數組有3個元素的等等...
3) Array(0,_*) 匹配數組以0開始
12.5.2 應用案例
package com.atguigu.chapter12.matchpart
object MatchArray { def main(args: Array[String]): Unit = { for (arr <- Array(Array(0), Array(1, 0), Array(0, 1, 0), Array(1, 1, 0), Array(1, 1, 0, 1),Array("hello", 90))) { // 對一個數組集合進行遍歷 val result = arr match { case Array(0) => "0" //匹配Array(0) 這個數組 // 說明 //1. 匹配有兩個元素的數組,而後將 將元素值賦給對應的x,y //2. => 使用xy case Array(x, y) => x + "=" + y //說明 //1. 以0開頭和數組 case Array(0, _*) => "以0開頭和數組" case _ => "什麼集合都不是" } println("result = " + result) }
} }
|
12.6 匹配列表
12.6.1 應用案例
package com.atguigu.chapter12.matchpart
object MatchList { def main(args: Array[String]): Unit = { //list是一個存放List集合的數組 //請思考,若是要匹配 List(88) 這樣的只含有一個元素的列表,並原值返回.應該怎麼寫 for (list <- Array(List(0), List(1, 0), List(0, 0, 0), List(1, 0, 0),List(88))) { val result = list match {
case 0 :: Nil => "0" //匹配List(0) case x :: y :: Nil => x + " " + y //匹配有兩個元素的List case 0 :: tail => "0 ..." //匹配以0開頭的,後面有0到多個元素的List case x :: Nil => x::Nil case _ => "something else"
} println(result) }
} }
|
12.7 匹配元組
12.7.1 應用案例
package com.atguigu.chapter12.matchpart
object MatchTuple {
def main(args: Array[String]): Unit = { //對一個元組集合進行遍歷 for (pair <- Array((0, 1), (1, 0), (1, 1),(1,0,2))) { val result = pair match { // case (0, _) => "0 ..." //是第一個元素是0的元組 case (y, 0) => y // 匹配後一個元素是0的對偶元組 case (a,b) => a + " " + b case _ => "other" //.默認 } println(result) }
} }
|
12.8 對象匹配
12.8.1 基本介紹
對象匹配,什麼纔算是匹配呢?,規則以下:
1) case中對象的unapply方法(提取器)返回some集合則爲匹配成功
2) 返回none集合則爲匹配失敗
12.8.2 應用案例1
package com.atguigu.chapter12.matchpart
object MatchObject { def main(args: Array[String]): Unit = { object Square { //咱們要編寫出正確的構造器和對象提取器,前提是你的業務邏輯是正確 def unapply(z: Double): Option[Double] = Some(math.sqrt(z)) def apply(z: Double): Double = z * z } // 模式匹配使用: //val number: Double = 8.0 val n = Square(9.0) //構建了一個Square n match { //說明 // 1. 當case 後面有Square(n),調用 Square的 unapply,進行對象提取 // 注意:unapply方法的參數 unapply(z: Double)的z 是number // 2. 若是返回的unapply 返回的是Some,就認爲匹配成功 // 3. 若是返回的是None ,就認爲不成功 // 4. 匹配成功後,會把返回值,賦給 Square(n) 的n case Square(n) => println("匹配到=" + n) case _ => println("nothing matched") } } }
|
12.8.3 應用案例1的小結
1) 構建對象時apply會被調用 ,好比 val n1 = Square(5)
2) 當將 Square(n) 寫在 case 後時[case Square(n) => xxx],會默認調用unapply 方法(對象提取器)
3) number 會被 傳遞給def unapply(z: Double) 的 z 形參
4) 若是返回的是Some集合,則unapply提取器返回的結果會返回給 n 這個形參
5) case中對象的unapply方法(提取器)返回some集合則爲匹配成功
6) 返回none集合則爲匹配失敗
12.8.4 應用案例2
package com.atguigu.chapter12.matchpart
object MatchObject02 { def main(args: Array[String]): Unit = {
val namesString = "Alice,Bob" //說明 // 1. 對namesString 進行對象匹配
namesString match { //1. 這裏Names(first, second, third)就會調用 unapplySeq //2. unapplySeq 若是返回了some集合,就會一次將結果賦給first, second, third //3. unapplySeq 返回的some集合中的結果的個數要和 case 提取的參數匹配 //4. 返回none 表示匹配失敗,即對象提取失敗 case Names(first, second, third) => { println("the string contains three people's names ok!") // 打印字符串 println(s"$first $second $third") } case _ => println("nothing matched") }
} }
object Names { //條件知足,返回 Some,條件不知足,返回None def unapplySeq(str: String): Option[Seq[String]] = { if (str.contains(",")) Some(str.split(",")) else None } }
|
12.8.5 應用案例2的小結
1) 當case 後面的對象提取器方法的參數爲多個,則會默認調用def unapplySeq() 方法
2) 若是unapplySeq返回是Some,獲取其中的值,判斷獲得的sequence中的元素的個數是不是三個,若是是三個,則把三個元素分別取出,賦值給first,second和third
3) 其它的規則不變.
12.9 變量聲明中的模式
12.9.1 基本介紹
match中每個case均可以單獨提取出來,意思是同樣的.
12.9.2 應用案例
package com.atguigu.chapter12.matchpart
object VarPattern { def main(args: Array[String]): Unit = {
val (x, y) = (1, 2) // x = 1 y = 2 val (q, r) = BigInt(10) /% 3 //說明 q = BigInt(10) / 3 r = BigInt(10) % 3 val arr = Array(1, 7, 2, 9) val Array(first, second, _*) = arr println(first, second) println("q=" + q + " r=" + r) //案例演示+說明
} } |