XY个人记
目录
七、List集合及基本操作、List集合常用方法、Set 集合
上代码喽:无参函数、局部函数、默认参数函数、变长参数函数、匿名函数、高阶函数、递归函数
十四、下面把九-十三 所有的代码都放到一起,里面包含了详细的介绍
一、Scala介绍
Scala是一种现代化的多范式编程语言,旨在以简洁,优雅和类型安全的方式表达常见的编程模式。 Scala由Martin Odersky创建,并于2003年发布了第一个版本,Scala顺利地整合了面向对象和功能语言的功能。本教程将以简单易读的方式来讲解Scala的基础知识。
Scala 是一门多范式(multi-paradigm)的编程语言,设计初衷是要集成面向对象编程和函数式编程的各种特性。
Scala 运行在Java虚拟机上,并兼容现有的Java程序。
Scala 源代码被编译成Java字节码,所以它可以运行于JVM之上,并可以调用现有的Java类库。
二、Scala 数据类型
Scala 与 Java有着相同的数据类型,但是scala没有java中的原生类型。
数据类型 | 描述 |
Byte | 8位有符号补码整数。数值区间为 -128 到 127 |
Short | 16位有符号补码整数。数值区间为 -32768 到 32767 |
Int | 32位有符号补码整数。数值区间为 -2147483648 到 2147483647 |
Long | 64位有符号补码整数。数值区间为 -9223372036854775808 到 9223372036854775807 |
Float | 32 位, IEEE 754标准的单精度浮点数 |
Double | 32 位 IEEE 754标准的单精度浮点数 |
Char | 16位无符号Unicode字符, 区间值为 U+0000 到 U+FFFF |
String | 字符序列 |
Boolean | true或false |
Unit | 表示无值,和其他语言中void等同。用作不返回任何结果的方法的结果类型。Unit只有一个实例值,写成()。 |
Null | null 或空引用 |
Nothing | Nothing类型在Scala的类层级的最低端;它是任何其他类型的子类型。 |
Any | Any是所有其他类的超类 |
AnyRef | AnyRef类是Scala里所有引用类(reference class)的基类 |
三、变量声明
在 Scala 中,使用关键词 "var" 声明变量(声明后不可更改),使用关键词 "val" 声明常量(声明后是可以被更改的)。变量的类型在变量名之后等号之前声明。定义变量的类型的语法格式如下:
val name1: String = "string"
var name2: String = "scala"
val num1: Int = 12
val num2: Int = 17
// 表达式
val test1: Int = {
println("aaa")
val r = {
println("bbb")
100
}
r
}
在 Scala中声明变量和常量不一定要指明数据类型,在没有指明数据类型的情况下,其数据类型是通过变量或常量的初始值推断出来的。所以,如果在没有指明数据类型的情况下声明变量或常量必须要给出其初始值,否则将会报错。
四、Scala 运算符、算术运算符
Scala 内置运算符:
算术运算符
关系运算符
逻辑运算符
位运算符
赋值运算符
算术运算符
+ 加号
- 减号
* 乘号
/ 除号
% 取余
赋值运算符
运算符 | 描述 |
= | 简单的赋值运算,指定右边赋值给左边的。 |
+= | 相加后再赋值,将左右两边的相加后再赋值给左边的。 |
-= | 相减后再赋值,将左右两边的相减后再赋值给左边的。 |
*= | 相乘后再赋值,将左右两边的相乘后再赋值给左边的。 |
/= | 相除后再赋值,将左右两边的相除后再赋值给左边的。 |
%= | 求余后再赋值,将左右两边的求余后再赋值给左边的。 |
<<= | 按位左移后再赋值 |
>>= | 按位右移后再赋值 |
&= | 按位与运算后赋值 |
^= | 按位异或运算符后再赋值 |
|= | 按位或运算后再赋值 |
五、Scala 条件判断、循环
代码-下面直接上代码包含了案例:
package com.jeffrey
import scala.collection.immutable
import scala.util.control.Breaks
/**
* Scala入门-判断、循环 模拟java break.continue 9*9 乘法表
*/
object HelloWord {
def main(args: Array[String]): Unit = {
val name1: String = "string"
// 表达式
val test1: Int = {
println("aaa")
val r = {
println("bbb")
100
}
r
}
println ("test1="+test1)
var name = "aa"
println("name:" + name)
println(s"name : ${name}")
// 多行字符串用三个双引号来表示分隔符,格式为:""" ... """
var str=
"""
|a
|b
|c
|d
""".stripMargin
println(str)
val num = 6
val res = if(num<5) {
println("小于五");
"a"
} else if (num > 10){
println("大于10")
"b"
} else {
println("5 和 10 之间")
"c"
}
val res1 = if(num>5) 0 else 1
println(s"res1:${res1}")
//简易数组
val arr: Range.Inclusive = 0 to 10 //是一个闭区间
val arr1: Range = 0.until(20) // 是一个半闭半开区间
val arr2: Range.Inclusive = 0.to(10,2) // 到10解释 步长为2
val arr3: Range = Range(0,10) // 等价于until
println(arr)
println(s"arr1:${arr1}")
println(s"arr2:${arr2}")
println(s"arr3:${arr3}")
val len = arr.length
var i = 0
//break 操作
val loop = Breaks
loop.breakable(
while(1 < len){
println(s"第${i}个元素是${arr(i)}")
if(i==3) {
loop.break() // 相当于Java里面的break
}
i += 1
}
)
val arrays: Array[Int] = (2 to 10).toArray
// for 循环的守护模式
for (array <- arrays if array < 5){
println(array)
}
// 用for循环实现break 和 continue
println("模拟break循环")
for(array <- arrays if array <= 5){
println(array)
}
println("模拟continue循环")
for(array <- arrays if array != 5){
println(array)
}
println("九九乘法表")
for(i <- 1 to 9){
for (j <- 1 to 9 if j<=i){
print(s"${j} * $i = ${i*j} ")
}
println()
}
for(i <- 1 to 9){
for (j <- 1 to i){
print(s"${j} * $i = ${i*j} ")
}
println()
}
// 两个for循环写在一起 代码块可以用一个{}
for(i <- 1 to 9;j <- 1 to i){
print(s"${j} * $i = ${i*j} ")
if (j==i) println()
}
for{
i <- 1 to 9 // 第一层for循环
j <- 1 to i // 第二层for循环
}{
print(s"${j} * $i = ${i*j} ")
if (j==i) println()
}
//for循环中可以绑定临时变量
val names = Array("hadoop","hdfs","yarn","","hive")
for {name <- names
nameTem = name.trim // 临时变量是val 是不可被修改的
if !nameTem.isEmpty}{
println(name)
}
//关键字 yield 生成一个新的集合,基于现有的集合生成一个新的集合 叫做:for循环的推导式
val array1: Array[Int] = (2 to 10).toArray
val newar1: Array[Int] = for(ar1 <- array1) yield {
ar1 * 2
}
println(array1.mkString("<","-",">"))
println(newar1.mkString("<",",",">"))
}
}
六、数组、元组
数组的声明和赋值
var book:Array[String] = new Array[String](3)
book(0) = "Haoop"; book(1) = "Hive"; book(2) = "Hbase"
元组 Tuple 元组里面可以是Scala里面的任意有效类型
最小的单元是一元组(但一般不用),最常用的是二元组,最多允许22元组,
元组中的类型是用val修饰,不可重新赋值,但是可以改变赋值对象中的属性或变量
元组底层对应的是Tumle 类型的class
代码-看代码一目了然里面有详细注释:
package com.jeffrey
import scala.collection.mutable.ArrayBuffer
/**
* 数组、元组
*/
object ArrayDemo {
def main(args: Array[String]): Unit = {
// 定长数组 - 不可变长度
// 数组的定义
val arr: Array[Int] = Array(1,2,3,4,5,6)
// 定义一个长度为5的数组
val arr1 = new Array[Int](5)
println(s"arr:${arr.mkString(",")}")
println(s"arr1:${arr1.mkString(",")}")
// 数组和Java一样 索引从0开始
println(s"数组的第一个元素是:${arr(0)}")
//println(arr(6)) // 数组越界
// 循环遍历数组
for(a <- arr){
println(s"数组的每一个元素是:$a")
}
// 变长数组 -- 长度可以改变ArrayBuffer
val arrbu = ArrayBuffer[Int]()
// 添加数组元素用+= 添加一个定长数组 用++=
arrbu += 12
arrbu += 12
arrbu += (1,2,3,4,5,6,7,8,9)
arrbu ++= Array(11,22,33,44,55,66,66,66,22) //添加一个定长的数组到一个变长的数组中
// 添加元素到指定位置,从第0个位置开始计算
arrbu.insert(2,666)
println(arrbu.mkString(","))
//删除数组的元素
arrbu.remove(1)
arrbu.remove(1,6) // 删除索引为1~6 的元素
arrbu -= 55 //删除指定元素
arrbu -= 66 //重复数据只能删一次,如果数据不存在,就不进行任何操作
arrbu -=(66,22,11)
println(arrbu.mkString(","))
// 更新 是基于索引的
arrbu(5) = 10 //更新替换指定位置的元素
println(arrbu.mkString(","))
// 获取值
println(arrbu(6))
val arr2 = arrbu.toArray //不可变数组
val arr3 = arrbu.toBuffer //可变数组
// 数组强转
val arr4: Array[Any] = Array(1,"scala",false)
val ints: Int = arr4(0).asInstanceOf[Int]
val strs: String = arr4(1).asInstanceOf[String]
val bools: Boolean = arr4(2).asInstanceOf[Boolean]
//元组 Tuple 元组里面可以是Scala里面的任意有效类型
// 最小的单元是一元组(但一般不用),最常用的是二元组,最多允许22元组,
// 元组中的类型是用val修饰,不可重新赋值,但是可以改变赋值对象中的属性或变量
// 元组底层对应的是Tumle 类型的class
// 一元组
val tup: Tuple1[Int] = Tuple1(2)
println(tup._1)
// 二元组
val tup2: (String, Int) = Tuple2("1",2)
println(tup2._1 + "," + tup2._2)
val tup3 = tup2.swap // swap 二元组数组交换位置
println(tup3._1 + "," + tup3._2)
// 元组可以嵌套进行 (元组可以放到数组里 数组也可放到元组里)
val tup4 = Tuple3(("java","html",("redis","scala","C++")),("spring","mybatis"),"6")
println(tup4._1._3._2)
}
}
七、List集合及基本操作、List集合常用方法、Set 集合
常用集合类型的应用:
Scala List:List的特征是其元素以线性方式存储,集合中可以存放重复对象。
Scala Set:Set是最简单的一种集合。集合中的对象不按特定的方式排序,并且没有重复对象。
Scala Map:Map 是一种把键对象和值对象映射的集合,它的每一个元素都包含一对键对象和值对象。
Scala Option: Option[T] 表示有可能包含值的容器,也可能不包含值。
Scala 元组:元组是不同类型的值的集合 元组在上面已经定义了
注:Scala程序使用Option非常频繁,在Java中使用null来表示空值,程序需要关心那些变量可能
是null,代码中很多地方都要添加null关键字检测,不然很容易出现NullPointException。但一但
出现,很难查出为什么出现NullPointerException。Scala的Option类型可以避免这种情况,因此
Scala应用推荐使用Option类型来代表一些可选值。使用Option类型,就可以清晰的看出这种类型的
值可能为None。
代码-上代码:
package com.jeffrey
import java.util
import scala.collection.mutable.ListBuffer
import scala.collection.JavaConverters._
import scala.collection.mutable
/***
* List集合及基本操作、List集合常用方法、Set 集合
*/
object ListDemo {
def main(args: Array[String]): Unit = {
// List集合
// 不可变集合
val list: List[Int] = List(1,2,3,4,5,6)
// 获取元素
println(s"获取数组的第一个元素:${list(0)}")
println(s"获取数组的头部元素:${list.head}")
println(s"获取数组除去头部之外的所有元素:${list.tail}")
println(s"获取数组的尾部元素:${list.last}")
println(s"获取数组除去尾部之外的元素:${list.init}")
// 拼接元素
val list1: List[Int] = 10::list
println(list1.mkString(","))
val list2: List[Int] = 10::20::30::40::50::60::Nil // 左链接 Nil代表一个空集合
println(list2.mkString(","))
val list3: List[Int] = Nil.::(100).::(200).::(300).::(400).::((500)).::(600) // 右连接
println(list3.mkString(","))
// list里面元素不能被更新
//list(0) = 100 报错
//println(list(0)) Error:(25, 9) value update is not a member of List[Int] list(0) = 100
// 构建可变的List
val list4: ListBuffer[Int] = ListBuffer(0,1,2,3,4,5,6,7)
// 添加元素
list4 += 8
list4 += 9
list4 ++= Array(10,11,12)
list4 ++= List(13,14,15,16)
// 更新指定位置元素
list4(0) = 100
// 指定位置添加元素
list4.insert(1,666)
for(a <- list4){
println(a)
}
println("------------------------------")
// 删除元素
list4 -= 100
list4 --= List(11,666,13)
println(list4.mkString(","))
// 删除指定位置元素
val resRm = list4.remove(0)
println(s"返回删除的元素:${resRm}")
println(list4.mkString(","))
// 集合转换成不可变集合
list4.toList
list4.toSet
//使用java集合
val listJava = new util.ArrayList[String]()
listJava.add(0,"zz")
//java List转换成Scala List 需要引入scala.collection.JavaConverters._ 包
val scalaList =listJava.asScala
//Scala List 转换成 java List
val listJava1 = scalaList.asJava
// List集合常用方法
val list5 = List(1,2,3,4,5,6)
//list 反转
println(list5.reverse)
// 拉链操作 两组集合转换成 一个二元组 zip:以最少的元素为准 zipAll:不够可以补充
println(list5.zip(List(7,8,9)))
println(list5.zip(List(10,11,12,13,14,15,16)))
println(list5.zipAll(List(20,21),-1,-2))
//数组 List 互相转换
val list6: List[Int] = (0 to 6).toList
val arr: Array[Int] = list6.toArray
val str: String = list6.toString()
println(str)
// foreach 没有返回值所以一般用于打印输出
list6.foreach(v => {
println(v)
})
//可简化为
list6.foreach(println)
// map对集合的每个元素处理,map是有返回值的
println(list6.map(2 * _))
val mapList: List[Unit] = list6.map(v => {
println(2 * v)
})
val mapList1: List[List[Int]] = list6.map(v => {
(1 to v).toList
})
mapList1.foreach(println)
println("----------------------------")
//flatMap对集合中每个元素的处理 使用给定函数 返回一个新的集合
// flatMap在map的基础上进行了一次扁平化的操作
// 如上面的操作 map返回的是一个list,flatMap是把map返回的每个list里面的数据结合起来做一个大的list
val flatMapList: List[Int] = list6.flatMap(v => {
(1 to v).toList
})
flatMapList.foreach(println)
// filter 数据过滤 filter
val fter: List[Int] = list6.filter(v => v % 2 == 0) //返回偶数 对集合中对2求余等于0的返回
fter.foreach(println)
val fter1: List[Int] = list6.filterNot(v => v % 2 == 0) // filterNot与filter相反
//reduce 数据聚合
val reduce: Int = list6.reduce((a:Int, b:Int) => {
// a 是 list里面的head元素,是上一个数据处理的临时聚合值
// b是集合里面的元素
println(s"a=${a} b=$b")
a + b
})
println(s"reduce=$reduce")
// fold 和 reduce 功能差不多,区别是flod可以给定一个初始值
// a 是 list里面的head元素,是上一个数据处理的临时聚合值
// b是集合里面的元素
// fold 指定a和b必须是同一类型的
val fold = list6.fold(10)((a:Int,b:Int) => {
println(s"a=${a} b=$b")
a + b
})
println(fold)
list6.foldLeft("")((a,b) => { // 执行过程从左往右
println(s"a=${a} b=$b")
a + b
})
// a 是集合里面的元素
// b 是 list里面的head元素,是上一个数据处理的临时聚合值
list6.foldRight("")((a,b) => { // 执行过程从右往左
println(s"a=${a} b=$b")
a + b
})
val list7 = List(6,3,1,2,4,5,0,8)
// 排序默认是升序排序
println(list7.sorted)
val list8: List[Int] = List(1,2,3,4,5,6,7,8,9,10,11,12)
// 根据指定函数的返回值进行排序
println(list8.sortBy(v => {v.toString}))
println(list8.sortBy(v => v % 4))
//groupBy返回一个map集合
println(list8.groupBy(v => v % 4))
/**** Set 集合 ****/
// Set集合 元素是不重复的,并且元素是无序的
// 不可变的Set
val set1: Set[Int] = Set(1,2,3,4,5,6,6,1,3,6)
println(set1.toString())
//添加一个新的集合(set1 + 12) ==> 是构建一个新的Set集合,原来的集合是不变
val set2: Set[Int] = set1 + 12
println(set2.toString())
val set3 = set1 ++ Set(7,8,9)
println(set3.toString())
val set4 = set3 - 8 // 是构建一个新的Set集合,原来的集合是不变
println(set4.toString())
// map 高阶函数和 list 是差不多的,区别是Set会去重
val set5 = set4.map(v => v * 2)
println(set5.toString())
// 访问
val set6 = set5(8)
println(s"8这个元素是否存在集合中:${set6.toString()}")
// 可以对集合set1进行去重 先转换成set在转换成list 但是顺序会被打乱
val listSet = List(1,1,2,2,3,3,4,4,5,5,6,6,6)
println(listSet.toList.toSet)
// 可变的Set集合 immutable 不可变的 mutable 可变的
val mutleSet = mutable.Set[Int]()
mutleSet += 12
mutleSet += 16
mutleSet += (17,18,19)
mutleSet ++= Array(6,7,8)
/*mutleSet -= 12
mutleSet -= 16
mutleSet -= (17,18,19)
mutleSet --= Array(6,7,8)*/
mutleSet(0) = true //set 集合添加一个元素
mutleSet(12) = false //set 集合删除一个元素
println(mutleSet.toString())
//mutleSet.toMap // 要求set集合是一个二元组
// Map 是一个键值对的集合
// 不可变的Map
val tst: (String, Int) = "a" -> 1
val map1: Map[String, Int] = Map("a" -> 1,"b" -> 2,"b" -> 2)
val map2 = Map(("a",1),("b",1),("c",1))
println(map1.get("a")) //Some(1)
println(map1.get("c")) //None
println(map1("a"))
//getOrElse 如果存在则返回存在的值 如果不存在则返回设置的默认值
println(map1.getOrElse("a",100))
println(map1.getOrElse("c",100))
// 可变的map 默认类型Nothing
val meMap: mutable.Map[Nothing, Nothing] = mutable.Map()
val map3: mutable.Map[String, Int] = mutable.Map()
// 添加元素
map3 += "d" -> 1
map3 += "e" -> 2
map3 += "f" -> 3
map3 += "f" -> 6
map3 ++= map1
// 删除元素是基于key去删除
map3 -= "a"
map3("c") = 7
println(map3.toString())
// map遍历
for (m <- map3){
println(s"key=${m._1} value=${m._2}")
}
for((key,vale) <- map3){
println(key + "," + vale)
}
map3.map(r => {
println(r._1 + "-" + r._2)
})
}
}
八、Scala 方法与函数
Scala 有方法与函数,二者在语义上的区别很小。Scala 方法是类的一部分,而函数是一个对象可以赋值给一个变量。换句话来说在类中定义的函数即是方法。
Scala 中的方法跟 Java 的类似,方法是组成类的一部分。
Scala 中的函数则是一个完整的对象,Scala 中的函数其实就是继承了 Trait 的类的对象。
Scala 中使用 val 语句可以定义函数,def 语句定义方法。
上代码喽:无参函数、局部函数、默认参数函数、变长参数函数、匿名函数、高阶函数、递归函数
package com.jeffrey
/**
* Scala函数
* 无参函数、局部函数、默认参数函数、变长参数函数、匿名函数、高阶函数、递归函数
*/
object FunctionDemo {
def main(args: Array[String]): Unit = {
def max(x:Int,y:Int):Int={
if(x > y){
x
} else {
y
}
}
val m: Int = max(5,7)
println(m)
// 无参函数
def f1(): Unit ={
println("无参函数F1")
}
f1()
f1
def f2{
println("无参函数F2")
}
f2
//局部函数
def f3 = {
println("进入函数F3")
f4()
def f4()= {
println("局部函数---进入函数F4")
}
}
f3
//默认参数的一个函数
def sayName(name:String = "小明",say:String = "Hi"): Unit ={
println(s"我叫:${name}")
println(s"$say, $name")
}
sayName(say="Hello",name = "张三")
// 变长参数 :可变长度参数,Scala允许指名函数的最后一个参数是可以重复的,
// 多个参数必须定义到参数列表的最后,只能有一个变长参数
def printCources(c:String*): Unit ={
c.foreach(cs=>{
println(s"变长参数:$cs")
})
}
printCources("数学","英语")
def printCources1(name:String,age:Int,cours:String*): Unit ={
cours.foreach(co => {
println(s"name=$name , age=$age ,cours:$co")
})
}
val couArr = Array("理综","英语","数学","语文")
//cous:_* 打印数组的每个元素,表示传递的是数组的每一个,并不是整个数组
printCources1("张三",18,couArr:_*)
// 函数复制给变量 "函数名称 + 空格 + _"
// 变长参数是一个集合 funcRes: (String, Int, Seq[String])
val funcRes: (String, Int, Seq[String]) => Unit = printCources1 _
funcRes("函数给变量",20,couArr);
//匿名函数 格式:(参数列表) => {函数体}
// var funcRes = (x:Int,y:String) = > {println("匿名函数")}
val res = (x:Int,y:Int) => {
if (x > y){
println(s"${x} 大于或等于 ${y}")
} else {
println(s"${x} 小于 ${y}")
}
}
res(1,6)
//高阶函数 直接将某个函数作为参数传入其他函数,接收其他函数作为参数的函数就称之为高阶函数
// 定义一个高阶函数
def greeting(name:String,func:(String) => Unit): Unit ={
func(name)
}
def sayHello(names:String): Unit ={
println(s"Hello ${names}")
}
greeting("Scala",sayHello)
greeting("Java",(a:String) => {println(s"a:${a}")})
// 高阶函数简化写法
greeting("C++",(a:String) => println(s"${a}"))
greeting("web",(a) => println(s"${a}"))
greeting("Html",a => println(s"${a}"))
greeting("jsp",println(_))
def opera(a:Int,b:Int,funcs:(Int,Int) => Int):Unit={
println("Func=" + funcs(a,b))
}
opera(12,66,(x:Int,y:Int) => {x + y})
opera(66,77,_+_)
def operas(aa:Int,bb:Int,func:(Int,Int) => Int)={
println(func(aa,bb))
}
operas(6,6,(xx:Int,yy:Int) => {6*6})
operas(6,6,_*_)
// 递归函数
def rescurFunc(n:Int): Int ={
if(n<=1) 1 else n * rescurFunc(n-1)
}
println(rescurFunc(6))
// 高阶函数之Map
val resMap: Array[Int] = Array(1,2,3,4,5).map(2 * _)
//等价于
val resmap = Array(1,2,3,4,5).map((a:Int) => {2 * a})
println(resmap.mkString("_"))
}
}
九、伴生类和伴生对象
定义:如果在一个scala文件中,分别存在一个class和一个object,而且class和object的名称完全一样,那么称这个class为object的伴生类,object称为class的半生对象
作用:伴生类和伴生对象之间可以相互访问私有属性和方法
十、apply 方法
定义在object中:表示提供一种快捷的对象创建方式,创建的对象就是apply方法返回的数据类型,创建对象的调用放射就是object名称+apply函数的参数列表
定义在class中,表示提供一种快捷的数据获取方式,类似list集合数据获取方式 eg:list(0)
十一、update 方法
只能定义在class中,标识提供一种便捷的数据更新/插入的方法,类似数组的更新 eg:arr(0) = 100
update函数中参数至少两个,参数列表的最后一个参数在调用的时候写在等号后面,其他的写在等号前面
十二、scala泛型
基本和Java一样,区别在于:Java使用<>表示泛型,scala使用[]表示泛型
泛型可以出现在class名称后面以及方法名称后面
class Student[T]
def add[T](t:T)
上下界:
[A1 >: A] : 表示A是A1的下界,也就是A是A1的子类
[A1 <: A] : 表示A是A1的上界,也就是A是A1的父类
协变/逆变:
[+T] : 协变,如果有一个类C定义为C[T],而且A是B的父类,那么C[A]是C[B]的父类
[-T] : 逆变,如果有一个类C定义为C[T],而且A是B的父类,那么C[B]是C[A]的父类
[T] : 正常定义,如果有一个类C定义为C[T],而且A是B的父类,那么C[A]和C[B]之间没有关系
十三、隐式转换
注意:隐式转换函数只能转换一次
隐式转换函数
将一个对象通过定义的隐式转换函数转换成为另一个对象,主要在于某一个对象在调用某个方法的时候,
该对象实际上没有该方法,可以通过隐式转换将该对象转换为具有该方法的其他对象(隐式转换函数在当前作用域中存在)
隐式转换对象
在函数的定义过程中,可以给定默认的输入参数,而且可以指定默认的参数是隐式转换对象,当该API被调用的时候,
会自动的从当前作用域中获取该隐式转换对象,比如List集合排序的时候,使用的排序器就是一个隐式转换对象
核心:定义隐式转换函数,即 implicit conversion function,用implicit修饰函数或者方法
scala默认会使用两种隐式转换
-1. 源类型,或者目标类型的伴生对象内的隐式转换函数
-2. 当前程序作用域内的可以用唯一标识符表示的隐式转换函数
十四、下面把九-十三 所有的代码都放到一起,里面包含了详细的介绍
test运行测试主类
package com.jeffrey.ObjectDemo
import java.security.KeyStore.TrustedCertificateEntry
object test {
def main(args: Array[String]): Unit = {
/* val person = new Person()
person.name = "jeffrey"
person.age = 18
person.eat()
*/
val person = new Person("haixia",18)
println(person.eat())
/*
伴生类和伴生对象
定义:如果在一个scala文件中,分别存在一个class和一个object,而且class和object的名称完全一样,那么称这
个class为object的伴生类,object称为class的半生对象
作用:伴生类和伴生对象之间可以相互访问私有属性和方法
*/
person.prints1() //半生对象和半生类
/*
apply 方法
定义在object中:表示提供一种快捷的对象创建方式,创建的对象就是apply方法返回的数据类型,创建对象的调用方式
就是object名称+apply函数的参数列表
定义在class中,表示提供一种快捷的数据获取方式,类似list集合数据获取方式 eg:list(0)
*/
// 调用object中
val v: Person = Person("张无忌",16)
println("-----name:" + v.name)
println("-----age:" + v.age)
// 调用class中
println(person.apply("张三丰"))
/*
update 方法
只能定义在class中,标识提供一种便捷的数据更新/插入的方法,类似数组的更新 eg:arr(0) = 100
update函数中参数至少两个,参数列表的最后一个参数在调用的时候写在等号后面,其他的写在等号前面
*/
person("张三丰") = 100
println(person.name + "------------" + person.age)
/*case class */
//val stu = new Student("zhangsan",16)
val stu1 = Student("xiaoma",12)
println(stu1.name)
/*
scala泛型
基本和Java一样,区别在于:Java使用<>表示泛型,scala使用[]表示泛型
泛型可以出现在class名称后面以及方法名称后面
class Student[T]
def add[T](t:T)
上下界:
[A1 >: A] : 表示A是A1的下界,也就是A是A1的子类
[A1 <: A] : 表示A是A1的上界,也就是A是A1的父类
协变/逆变:
[+T] : 协变,如果有一个类C定义为C[T],而且A是B的父类,那么C[A]是C[B]的父类
[-T] : 逆变,如果有一个类C定义为C[T],而且A是B的父类,那么C[B]是C[A]的父类
[T] : 正常定义,如果有一个类C定义为C[T],而且A是B的父类,那么C[A]和C[B]之间没有关系
*/
/*
隐式转换
注意:隐式转换函数只能转换一次
隐式转换函数
将一个对象通过定义的隐式转换函数转换成为另一个对象,主要在于某一个对象在调用某个方法的时候,
该对象实际上没有该方法,可以通过隐式转换将该对象转换为具有该方法的其他对象(隐式转换函数在当前作用域中存在)
隐式转换对象
在函数的定义过程中,可以给定默认的输入参数,而且可以指定默认的参数是隐式转换对象,当该API被调用的时候,
会自动的从当前作用域中获取该隐式转换对象,比如List集合排序的时候,使用的排序器就是一个隐式转换对象
核心:定义隐式转换函数,即 implicit conversion function,用implicit修饰函数或者方法
scala默认会使用两种隐式转换
-1. 源类型,或者目标类型的伴生对象内的隐式转换函数
-2. 当前程序作用域内的可以用唯一标识符表示的隐式转换函数
*/
implicit def boolean2String(flag:Boolean):String = flag.toString
val str: String = true
implicit def int2String(flag:Int): String = flag.toString
val a:String = 666
a.trim()
}
}
Person类:
package com.jeffrey.ObjectDemo
//Person(name:String,age:Int) 是 主构造函数,会自动编译成属性
// 除了参数列表,函数体内包含可执行的代码
class Person(var name:String,var age:Int) { // 半生类
//属性的作用域默认为public
/*var name:String = _
var age:Int = _*/
println("--------start----------")
// 辅助构造函数
def this(){
this("hx",26) //第一行调用主构造函数,必须写在第一行
println("666")
}
// 辅助构造函数
def this(age:Int){
this()
this.age = age
}
def eat() ={
println(s"${name}已经${age}岁了,她正在吃东西……")
}
def prints1(): Unit ={
println("我是半生类")
Person.printlns()
}
def apply(name:String):String={
println(s"invoke apply ${name}")
this.name
}
def update (name:String,age:Int)={
println(s"invoke update ")
if(this.name == name){
this.age = age
}
}
println("--------end----------")
}
object Person { // 半生对象
private def printlns(): Unit ={
println("我是半生对象")
}
def apply(name:String,age:Int): Person = new Person(name,age)
}
模式匹配
package com.jeffrey.ObjectDemo
/**
* 模式匹配
* 在我们学过的java中switch case 只能对数值进行匹配
* Scala中
* 1.对值进行匹配
* 2.对配型进行匹配
* 3.对Array和List进行匹配
* 4.对case class进行配置
* 5.对有值或没值进行匹配
*
* 匹配的时候,是从上往下匹配的,所以限制条件比较严格的放在前面
*/
object PatternDemo {
def main(args: Array[String]): Unit = {
//1.对值进行匹配
def f1(num:Int)={
num match{
case 1 => {
println("num is 1")
}
case 2 =>{
println("num is 2")
}
case _ =>{
print("num is other^")
}
}
}
//2.对配型进行匹配
def f2(v :Any) = {
v match {
case v:Int =>{
println("is Int type")
}
case v:String =>{
println("is String type")
}
case _ =>{
println("is Other type")
}
}
}
// 3.对Array和List进行匹配
def f3(list:List[Int]):Int ={
list match {
case Nil => 0
case head :: Nil => head
case head :: tail => head + f3(tail)
}
}
//4.对case class进行配置
def f4(student: Student):Unit = {
student match {
case Student("zhangsan",12) => println(1)
case Student(_,12) => println(2)
case Student("zhangsan",_) => println(3)
case Student(_,_) => println(4)
}
}
//5.对有值或没值进行匹配
val map = Map("a"->1,"b"->2,"c"->3)
println(map.get("a"))
println(map("a"))
val option: Option[Int] = map.get("c")
println(s"option:${option}")
option match {
case Some(value) => println(s"Some value is :${value}")
case None => println("None")
}
}
}
Student类:
package com.jeffrey.ObjectDemo
/*
case class
Scala中的一种特殊的class,叫做 case class
case
class 就是class和object的一个整合,在变异的过程中会自动的生成class和object的相关代码,并且
在object中生成一个和class主构造函数通参数列表的apply方法,可以简化写object的过程.
---定义一个Student类
case class中默认的属性修饰符为public val,但是可以改变的,跟普通函数的定义是一样的,没有区别
case class中的属性最多允许为22个,跟元组中是一样的
一般比较常用于模式匹配
*/
case class Student (name:String,age:Int)
// 会默认生成object 的apply方法
object Student{
//def apply(name: String, age: Int): Student = new Student(name, age)
}
枚举类:
package com.jeffrey.ObjectDemo
/*
scala 枚举
枚举:scala不支持enum关键字,通过继承Enumeration类实现枚举
*/
object EnumDemo extends Enumeration {
def main(args: Array[String]): Unit = {
type EnumDemo = Value //type关键字:类型的别名
val FIRST,SECOND = Value
val THIRD = Value(10) //ID 为 10
val FIVE = Value("abc") // Name 为 abc
println(THIRD.id)
println(FIVE.id)
println(FIVE)
}
}
继承:
package com.jeffrey.ObjectDemo
trait A {
def h()
}
trait B
trait C {
var b : Int
val c : Double
def f()
val abc = "123"
def g(name:String): Unit ={
println(s"invoke trait C : ${name}")
}
}
trait D extends A {
override def h(): Unit = {
println("invoke D h")
}
}
class F extends C {
override var b: Int = 10
override val c: Double = 1.68
override def f(): Unit = {
println("invoke F ")
}
}
// 多个继承
trait MD extends A with B with C{
override def h(): Unit = {
println("invoke D h")
}
}
object M{
def main(args: Array[String]): Unit = {
val f = new F
println(f.b)
println(f.c)
println("--:"+f.f())
println(f.abc)
println(f.g(" TRAIT"))
}
}
十五、Scala异常处理
捕获异常
异常捕捉的机制和Java一样,如果有异常发生,catch字句是按次序捕捉的。因此,在catch字句中,越具体的异常越要靠前,越普遍的异常越靠后。 如果抛出的异常不在catch字句中,需要我们自己处理。
捕捉异常的catch子句,语法与其他语言中不太一样。在Scala里,借用了模式匹配的思想来做异常的匹配,因此,在catch的代码里,是一系列case字句。
import java.io.FileReader
import java.io.IOException
import java.io.FileNotFoundException
/* 异常的捕获 */
object TestException {
def main(args: Array[String]) {
try {
val f = new FileReader("input.txt")
} catch {
case ex: FileNotFoundException =>{
println("Missing file exception")
}
case ex: IOException => {
println("IO Exception")
}
}
}
}
catch字句里的内容跟match里的case是完全一样的。由于异常捕捉是按次序,如果最普遍的异常,Throwable,写在最前面,则在它后面的case都捕捉不到,因此需要将它写在最后面。
finally 语句
finally 语句不管是正常处理还是有异常发生时都需要执行的步骤:
import java.io.FileReader
import java.io.IOException
import java.io.FileNotFoundException
object TestFinally {
def main(args: Array[String]) {
try {
val f = new FileReader("input.txt")
} catch {
case ex: FileNotFoundException => {
println("Missing file exception")
}
case ex: IOException => {
println("IO Exception")
}
} finally {
println("Exiting finally...")
}
}
}