Scala
简介 :
1.运行在JVM上,
2.面向对象(OOP),
3.面向函数,
4.表达性强,
5.scala语句最后不用分号结束
scala中定义类 :
case calss product(var id:Int ,var category:String)
-
打印
println("hello,world")
-
定义变量
定义变量格式 :
val : 不可重新赋值变量 val name:String="zhangsan" var : 可重新赋值变量 var name:String="lisi" 更简洁的方式定义变量 var name="wnagwu"
*注意 : 优先使用val定义变量 , 如果变量需要重新赋值,才使用var
*惰性赋值
惰性赋值只有val可以 , var不可以
*注意 : 被lazy修饰的变量初始化值的时候是在第一次使用这个变量的时候才会被赋值,
值只会被计算一次,赋值一次,之后就不会更改了,
*(调用时才会加载到内存)
格式 : lazy用来实现惰性赋值的关键字 lazy val 变量名 = 表达式
*字符串
字符串使用双引号"" length : 字符串长度 var name="lisi" println(name.length) : 打印字符串长度
插值表达式 :
val name ="zhsngsan" val age = 18 val sex="nv" val info=s"name=${name},age=${age},sex=${sex} //前面必须加小写 s println(info) ----------------------------------------------- 打印结果为 : name=zhangsna,age=30,sex=male
使用三引号
代码中需要换行必须在代码中加入\n\r
换成三引号""" 后直接在代码上回车即可
如果字符串想保留原意,也可以使用三引号(比如三引号中包裹引号)
前面加"""三引号在代码上直接回车即可,定义结束时在加上"""三引号即可 : val sql ="""select * from user where name ="zhangsan""""
数据类型与操作符
运算符 :
定义两个变量 : val test = "abc" val test02 = "abc" 运算符 : == if (test==test02){println("符合条件")}else{println("不符合条件")} //打印结果 : 符合条件 运算符 : .eq() if (test.eq(test02)){println("符合条件")}else{println("不符合条件")} //打印结果 : 符合条件 与Java不一样,在scala中,可以直接使用==、!=进行比较,它们与equals方法表示一致。而比较两个对象的引用值,使用eq。(跟java相反。)
条件表达式
有返回值的if : val sex = "male" val result = if(sex.eq("male")) 1 else 0 //满足条件就把1赋值给result , 否则把0赋值给result
块表达式
块表达式 : 有返回值 ,
*注意 : 最后一行就是他的返回值
//块表达式,返回值为 2 val a = { println("1+1") 1+1 }
循环 ===
for循环 :
for表达式
1. 简单 :
//打印数字 1~10 : var nums=1.to(10) for(i <- nums) print(i+",")
//打印数字 1~10 中缀调用法:1 to 10 for(i <- 1 to 10)print(i+",")
2. 嵌套 : 外边循环一次,里边循环一圈
//使用嵌套for表达式打印4行3列的 * for (i <- 1 to 4 ;j <- 1 to 3){print("*");if(j==3)println(" ")}
3. 守卫
for循环表达式中可以添加判断语句,这个if判断就称为守卫
if像守卫一样,条件符合的才可以进入代码块中执行
//打印1~100之间的偶数,用守卫实现 for(i <- 1 to 100 if i % 2 == 0)print(i + " ")
4. 推导式 : yield关键字
使用yield的for表达式称之为推导式
该for表达式还会构建一个集合
//打印 10 , 20 , 30 , 40 , 50 , 60 , 70 , 80 , 90 , 100 val list = for(i <- 1 to 10 ) yield (i * 10 )
whlie循环 :
//打印1~10 var i = 1 while(i <= 10){ println(i) i=i+1 }
实现breakbre :
先导入import scala.util.control.Breaks._包
用berakable包裹for循环
import scala.util.control.Breaks._ breakable{ for(i <- 1 to 100){ if(i >= 50) break() else println(i) } }
实现continue :
1~100之间,不打印能整除3的数字
import scala.util.control.Breaks._ for(i <- (1 to 100)){ breakable{ if(i%3==0) break() println(i) } }
定义方法 ==========
def 方法名称 (参数名:参数类型,参数名:参数类型) : [返回类型] = {方法体}
1. 定义一个方法,实现两个整形数值相加,返回相加后的结果 def sum(a:Int,b:Int) : Int = a+b 2. 调用该方法 sum(4,7)
scala 方法参数 :
默认参数 : 定义方式法是给定一个默认值
//定义方法时给值 def sums (a:Int = 0,b:Int = 0) : Int = a+b //调用方法 sums() //打印结果为 0
带名参数 : 调用方法时,指定参数名称调用
//定义方法时给默认值 def sums(a:Int=0,b:Int=0):Int = {a+b} //调用方法 sums(a=6) //打印结果 : 6
变长参数 : 如果方法参数不固定,可动态指定参数,不限个数
//定义变长参数 def count(a:Int*):Int = {a.sum} //调用方法,传入参数 count(1,2,3,4,5,6) //打印结果 : 21
object demo20 { //变长参数 def sum(x:Int*): Unit ={ var result=0 for(i <- x){ result += i } println(result) } def main(args: Array[String]): Unit = { //变长参数,可以传递多个参数 sum(1,2,3,4,5) //打印结果为15 } }
scala 方法的调用 :
1. 后缀调用法
对象名.方法名(参数)
//Math.abs : 求绝对值 Math.abs(-22)
2. 中缀调用法
对象名 方法名 参数
//Math.abs : 求绝对值 Math abs -1
3. 花括号调用法
//Math.abs : 求绝对值 Math.abs{ -1 + -45 }
4. 无括号调用法
//定义方法 def m() {println("hello")} //调用方法 m()
函数 ==========
函数定义 :
val 函数变量名 = (参数名:参数类型, 参数名:参数类型....) => {函数体}
函数是一个对象
类似于方法 ,函数也有输入参数和返回值
函数定义不需要def定义
无需指定返回值的类型
方法和函数的区别 : 方法无法赋值给变量,函数可以
方法隶属于类或对象 ,运行时直接加载到JVM中 函数对象可以赋值给一个变量 , 运行时加载到堆内存中 函数是一个对象 , 继承自FunctionN 函数对象有apply curried toString tupled 这些方法 方法则没有 函数是对象,对象包含方法
定一个两个数相加的函数
//语法格式 : val a = ( x:Int,y:Int) => {x+y} //调用函数 a(1,2) //打印结果 : 3
方法转换函数 : 需要将方法转换为函数,作为变量传递的时候,就需要将方法转换为函数
//定义方法,两个数相加 def count(x:Int,y:Int):Int={x+y} //将方法转换为函数,赋值给变量 下划线 _ : 下划线是关键 val a = count _
数组 ==========
定长数组
定长数组的长度不允许改变
数组元素可变
-
使用[ ] 定义数组泛型
-
使用() 获取数组元素
//指定数组长度 var a = new Array[Int](10) //用元素直接初始化数组 var a = Array(1,2,3,4,5) //获取第三个元素3 println(a(2))
变长数组
长度可以动态调整
-
定义变长数组需要提前导入包 : import scala.collection.mutable.ArrayBuffer
-
元素的 : 增 , 删 , 改
+= 添加元素 -= 删除元素 ++= 追加
//创建长度为0的整数型变长数组(定义空的变长数组) val a = ArrayBuffer[Int]() //定义包含三个字符串的变长数组 var a = ArrayBuffer("java","hadoop","scala") //增加元素 s+="spark" //删除元素 s-="java" //追加 var i = ArrayBuffer("sqoop","zookeeper") s++=i
遍历数组
for循环直接遍历
//可变数组 var a = ArrayBuffer("hadoop","java","mysql") //for遍历 for(i <- a){ println(i) }
for下标遍历
//定义数组 val a = Array("java","hadoop","scala") //for根据下标遍历 for(i <- 0 to a.length-1 )println(a(i))
数组算法
//定义数组 val a = Array(1,2,3,4,5,6) //求和: sum a.sum //求最大值: max a.max //求最小值: min a.min //排序: sorted(升序) a.sorted //降序: sorted.reverse(降序) 先升序,再反转 a.sorted.reverse
元组 ==========
元组中可以放不同类型的元素
-
定义元组 : var a = (1,2,3,4)
1.var a = (元素1,元素2,...)
-
只有两个元素时 :
2.var a = 元素1 -> 元素2
定义元组 :
//定义一个元组,包含学生的编号,姓名,年龄,地址 var student = (1,"lzs",22,"beijing") //定义一个元组,包含学生的编号,姓名 var student = 1 -> "lzs"
访问元组 : _1 , _2 , _3
//定义一个元组,包含学生的编号,姓名,年龄,地址 var student = (1,"lzs",22,"beijing") //用 _1 , _2 , _3 访问元组 //获取第一个元素 1 student._1 //获取第二个元素 lzs student._2
列表 ==========
可变列表 和 不可变列表
* List(列表) :
元素可以重复
有先后顺序
不可变列表 都在immutable包中 默认导入
-
列表的长度 和 元素 都不可变
//使用List(元素1,元素2,...)创建一个不可变列表 var a = List("hadoop","java","mysql") //创建不可变空列表 var a = Nil //用 :: 创建一个不可变列表 必须以Nil结尾 var a = "hive" :: "hdfs" :: "mr" :: Nil
可变列表 都在mutable包中 需要导入
-
长度可变 元素可变
-
要使用可变列表,先要导入import scala.collection.mutable.ListBuffer
import scala.collection.mutable.ListBuffer //创建Int类型空的可变列表 var a = ListBuffer[Int]() //创建可变列表指定类型 var a =ListBuffer[String]("hadoop","java","hive") //拿列表中的第1个元素 根据下标 a(0) //往列表添加元素 += a+="HDFS" //定义一个新的可变列表 var i = ListBuffer("spark","flink") //往列表追加列表 ++= a++=i //更改元素 根据下标赋值 a(a.length-1) = "zookeeper" //删除元素 -= a-="spark" //转换为List 不可变列表 a.toList //转换为Array 定长数组 a.toArray
列表常用操作
//创建测试列表 var a =ListBuffer(1,2,3,4,5) //判断列表是否为空 isEmpty a.isEmpty //拼接列表 ++ var a1 = ListBuffer(6,7,8) a ++ a1 //获取首个元素 head a.head //获取首个之外的元素(除了首个元素都获取) a.tail //反转列表 a.reverse //获取前缀 take(2) : 获取前2个 a.take(2) //获取后缀 drop(2) : 除了前2个都要 a.drop(2) //扁平化 flaten : 要求集合里也是集合 //创建s列表接收 //a(1,2,3,4,5) 和 a1(6,7,8) 列表 var s = ListBuffer(a,a1) s.flaten //结果为 : ListBuffer(1, 2, 3, 4, 5, 6, 7, 8) //拉链zip: 组合成一个元素为元组的列表 a.zip(a1) //拉开unzip: 将一个包含元组的列表,解开成包含两个列表的元组 var i = a.zip(a1) i.unzip //打印结果: (ListBuffer(1, 2, 3),ListBuffer(6, 7, 8)) //转换字符串 toString方法 val a = 456 d.toString // 生成字符串 mkSring 可以将元素以分隔符拼接起来。默认没有分隔符 a.mkString //结果为 12345 a.mkString("-") //结果为 1-2-3-4-5 //并集: union (把两个和到一块) val a1 = List(1,2,3,4) val a2 = List(3,4,5,6) a1.union(a2) //结果为: List(1, 2, 3, 4, 3, 4, 5, 6) // 交集: intersect (两个都有的拿出来) a1.intersect(a2) //结果为: List(3, 4) //差集 diff 获取a1在a2中不存在的元素(看a1哪个再a2中没有) a1.diff(a2) //结果为: List(1, 2)
* Set (集) :
元素不重复
不保证插入顺序
注意 : 如果想混用不可变Set和可变Set,最好类前加完整包名路径。
val a = scala.collection.mutable.Set(1,2,3),这样不会产生任何歧义。
不可变集 :
//创建空不可变集 var a =Set[Int]() //给定元素创建 var a =Set[Int](1,1,2,3,4,5,6) //打印结果: Set(5, 1, 6, 2, 3, 4) //*注意: 不保证顺序,元素不能重复
可变集 :
不可变集 和 可变集 的创建方式一致
创建可变集需要先导入包 : import scala.collection.mutable.Set
//创建一个可变集 var a =Set(1,2,3,4) //往集中添加元素 a+=5 //移除集中元素1 a-1
* Map (映射) :
是由键值对组成
Map再scala中称为映射
不可变Map :
语法 :
//第一种 val map = Map(键->值,键->值,键->值,.....) //第二种 val map = Map((键,值),(键,值),(键,值),..)
//定义映射 var map = Map("lisi"->30,"wangwu"->40) //或 var map = Map(("lisi",30),("wangwu",40)) //根据key获取value map("lisi")
可变Map :
语法与不可变Map一致
需要手动导入: import scala.collection.mutable.Map
//定义一个可变映射 var map = Map("lisi"->30,"lzs"->22)
映射(Map)常用操作
//根据key修改value map("lzs")=23 //获取value: map("lzs") //获取所有key: map.keys map.keys //获取所有value: map.values map.values //遍历map集合 for((x,y) <- map) println(s"$x : $y") // getOrElse: 获取某一key对应的value,如果这个key不存在,返回-1 map.getOrElse("wangwu",-1) //增加一个键值对 map += ("wangwu" -> 40) //删除一个键值对 map -= "wangwu"
iterator (迭代器):
scala针对 每一类集合都提供了一个迭代器(iterator) 用来访问集合
迭代器基本操作 :
hasNext: 查询容器是否有下一个元素,有为true,没有为false next: 返回集合下一个元素 ,没有就抛出: NoSuchElementException(列表为空异常)
迭代器的基本状态 :
迭代完后保留在最后一个元素位置 再次使用则抛出: NoSuchElementException(列表为空异常)il
使用 while循环 和 for循环 逐个返回元素
while循环 : il
//创建一个列表 var list = List(1,2,3,4,5) //使用whlie循环和iterator(迭代器)来遍历列表 var iter = list.iterator //使用whlie循环来遍历列表 while(iter.hasNext){ //判断有没有下一个元素 println(iter.next) //获取下一个元素 }
for循环 :
//创建一个列表 var a = List(1,2,3,4,5) //迭代器iterator var iter = a.iterator //用for循环和iterator(迭代器)遍历 for(i <- a){println(i)}
函数式编程 (重点,重点,重点)
都是容器集合对象的方法 (方法的参数都是函数,参数都会传递到函数中):
-
1.遍历 : foreach
-
2.映射 : map
-
3.映射扁平化 : flatmap
-
4.过滤 : filter
-
5.是否存在 : exists
-
6.排序 : sorted , sortBy , sortWith
-
7.分组 : orderBy
-
8.聚合计算 : reduce
-
9.折叠 : fold
把函数当作参数传入方法:
//函数为参数 object demo21 { def main(args: Array[String]): Unit = { //定义方法,参数是函数,传入函数其实本质就是传入运算逻辑 def func(f:(Int,Int)=>Int): Unit ={ f(1,2) } //传入参数,参数是个函数 func((x,y)=>x+y) } }
1.
遍历foreach
语法: 集合对象.foreach(i : Int)=>println(i))
//定义一个列表 var a = List(1,2,3,4,5) //foreach遍历打印,参数都是函数 //(i:Int)=>{println(i)} 函数参数 => 函数体 a.foreach((i:Int) => println(i))
*使用类型推断简化函数定义
scala可以自动推断出集合的每个元素的参数类型
创建函数时可以省略参数列表的类型
//创建一个列表 var a = List(1,2,3,4,5) //使用类型推断简化函数定义foreach遍历打印 a.foreach(i=>println(i))
*使用下划线来简化定义函数
当参数在函数体中只出现一次,并且函数没有嵌套
//定义一个列表 val a = List(1,2,3,4,5) //使用下划线来简化定义函数foreach遍历打印 a.foreach(println(_)) //简写 a.foreach(println)
2.
map映射(一进一出)
map方法接收一个函数,
将这个函数应用到每一个元素,
返回一个新的集合
//定义一个列表 var a = List(1,2,3,4) //定义一个函数 (i:Int)=>{i+1} //把函数传入到map方法 a.map((i:Int)=>{i+1}) //简化 a.map(_+1)
3.
flatMap扁平化映射
map是将列表中的元素转换为一个List
flatten再将整个列表进行扁平化
可以把flatMap,理解为先map,然后再flatten
//理解映射扁平化 //定义一个集合 var a = List("hadoop hive spark flink flume", "kudu hbase sqoop storm") //映射map i=>split(" ") var b = a.map(i=>split(" ")) //扁平化flatten var c = b.flatten //使用faltMap简化操作 a.flatMap(_.split(" "))
4.
filter过滤
过滤一定条件的元素
//创建1~9列表 var a = (1 to 9).toList //过滤filter 过滤偶数 var b = a.filter((i:Int)=>i%3==0) //简化 var b = a.filter(i=>i%3==0) //简化 var b = a.filter(_%3==0)
5.
排序 :
sortde(默认排序) ,
sortBy(指定字段排序) ,
sortWith(自定义)
sortde默认排序
//创建一个列表 包含3, 1, 2, 9, 7 var a = List(3, 1, 2, 9, 7) //默认排序 降序 a.sorted
sortBy指定字段排序
根据传入的函数转换后再排序
//创建列表 var a = List("01 hadoop", "02 flume", "03 hive", "04 spark") //按单词字典序排序 sortBy var b = a.sortBy((i:String)=>i.split(" ")(1)) //简化 var b = a.sortBy(_.split(" ")(1))
sortWith自定义排序
//创建一个列表 var a = List(2,3,1,6,4,5) //降序自定义排序sortWith var b = a.sortWith((x:Int,y:Int)=>{if(x>y) true else false}) //简化 降序sortWith var b = a.sortWith((x,y)=>if(x>y) true else false) //简化 降序sortWith var b = a.sortWith(_>_)
6.
groupBy 分组
groupBy表示按照函数将列表分成不同的组
//创建一个元组列表 var a = List("张三"->"男", "李四"->"女", "王五"->"男") //按照性别分组 var b = a.groupBy(i=>i._2) //结果 Map(男 -> List((张三,男), (王五,男)), 女 -> List((李四,女))) //用map转换 //传入map映射的函数: (x)=>{x._1 -> x._2.length} var c = b.map(x=>x._1 -> x._2.length)
7.
reduce聚合操作
· reduce和reduceLeft效果一致,表示从左到右计算
· reduceRight表示从右到左计算
//创建集合 : 1,2,3,4,5,6,7,8,9,10 var a = List(1,2,3,4,5,6,7,8,9,10) //用reduce聚合 var b = a.reduce((x,y)=>x+y) //简化 var b = a.reduce(_+_)
8.
fold折叠
比reduce多了一个指定参数
会从参数开始依次聚合
//创建集合 : 1,2,3,4,5,6,7,8,9,10 var a = List(1,2,3,4,5,6,7,8,9,10) //fold折叠 var b = a.fold(5)((x:Int,y:Int)=>{x+y}) //简化 var b = a.fold(5)((x:Int,y:Int)=>{x+y}) //简化 var b = a.fold(5)(_+_) //打印结果 60
类 ====
1. 创建类和对象
使用class来定义一个类 class 类名 {} 使用new来创建对象 new 类名
2. 简写方式
如果类没有任何成员可以省略{} 构造器的参数为空 可以省略() class person
3. 定义和访问成员变量
使用var|val定义成员变量 对象直接使用成员变量名称来访问成员变量
4. 使用下划线初始化成员变量
String => null Int => 0 Boolean => false Double => 0.0 下划线初始化 : var|val 变量名:[类型] = _
5. 定义成员方法
//定义类 class Customer{ var name:String = _ var age:Int = _ def printHello(x:String) = { println(s"${x} , ${name}") //定义成员方法 } } object demo01 extends App { val customer = new Customer //创建对象 customer.name="lzs" //给成员变量赋值 customer.age=22 customer.printHello("你好") //调用成员方法 }
6. 访问修饰符
通过 private | protected 控制成员的可见性,
scala中没有public关键字,没有被 private | protected修饰的都是公共的
protected是,可以被子类访问
如果不需要任何get或set,可以将字段声明为: private[this]
//私有属性不能被外界访问 object demo03 { class Person { // 定义私有成员变量 private var name: String = _ private var age: Int = _ def getName() = name def setName(name: String) = this.name = name def getAge() = age def setAge(age: Int) = this.age = age // 定义私有成员方法 private def getNameAndAge = { name -> age } } def main(args: Array[String]): Unit = { val person = new Person person.setName("张三") person.setAge(10) println(person.getName()) println(person.getAge()) } }
7.自定义类构造器
//语法 : class 类名(var/val 参数名:类型 = 默认值, var/val 参数名:类型 = 默认值){ // 构造代码块 }
1.定义了类
2.定义了成员变量
3.给成员变量赋了值
4.定义了主构造器
package cn.test01 //自定义构造 class Person( var name:String= "",var age:Int= 0 , private var sex:String=""){ def setsex(sex:String)= this.sex = sex def getsex() = sex } object demo05 { def main(args: Array[String]): Unit = { val lzs = new Person("lzs", 22, "男") val sex = lzs.getsex() println(sex) } }
8.辅助构造器
针对不同的业务场景,
可以设计不同的辅助构造器
主要体现改造参数不同
(定义辅助构造器跟方法一样需要用 def关键字定义 但是名字必须叫 this )
//语法 def this(参数:类型,参数:类型){ //第一行必需要调用主构造器或其他构造器 //构造器代码 }
class Person (var name:String="",var sex:String="" ){//主构造器 //辅助构造器 def this(arr:Array[String])={ // 第一行需要调用主构造器或者其他构造器 this(arr(0),arr(1)) //this } } object demo06 extends { def main(args: Array[String]): Unit = { val person = new Person(Array("lzs","男"))//用他的辅助构造器创建对象"lzs","男" println(person.name) //打印 println(person.sex) //打印 } }
9.单例对象
scala中没有static(静态成员)
想要定义类似java中的静态变量或方法
就要用到scala中的object--单例对象
跟类的定义很像 就是把class换成object 在object中定义成员变量类似java的静态变量 可以使用object直接引用成员变量
//单例对象中定义方法 : //单例对象,定义一个能够打印分割线(20个减号)的方法 //在main方法调用该方法,打印分割线 object dy { def dayin() = { println("---" * 20) } } object demo08 extends App { dy.dayin() }
10.工具类
//定义一个DateUtil单例对象,定义日期格式化方法(format) //使用SimpleDateFormat将日期转换为字符串 object demo09 { object DateUtil { // 在object中定义的成员变量,相当于Java中定义一个静态变量 //创建时间格式转换对象 val simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm") //定义format方法,相当于java静态方法 def format(date: Date) = simpleDateFormat.format(date) } def main(args: Array[String]): Unit = { println(DateUtil.format(new Date())) } }
11.main方法
def main(args : Array[String]) : Unit={ //方法体 } 或 object 单例对象名 extends App { //方法体 }
12.伴生对象
java中经常会有一个类有实例成员和静态成员
在scala中要实现类似效果,可以使用伴生对象实现
一个class和object有同样的名字, 这个class就称为伴生类 这个object就称为半生对象
伴生类和伴生对象可以互相访问private私有属性
private[this] :
如果某个成员的权限设置为private[this],表示只能在当前类中访问。伴生对象也不可以访问
//编写一个英雄Hero类,定义一个作战方法fight(), //编写一个Hero伴生对象,定义一个私有变量WEAPON,用于保存作战武器的名称,比如方天画戟 //在Hero类的作战方法fight()中,引用Hero伴生对象的私有变量WEAPON,打印 "我要用【WEAPON】作战了" object demo10 { class Hero{//伴生类 def fight()={println(s"我要用${Hero.WEAPON}打架了")} } object Hero{//伴生对象 private var WEAPON= "方天画戟" } def main(args: Array[String]): Unit = { val hero = new Hero println( hero.fight()) } }
private[this] :
private可以访问 private[this]伴生对象都访问不了
//private[this] 修饰的伴生对象也访问不了 private修饰的可以 object demo11 { //伴生类 class Person(private var name: String = "lzs") {} object Person { //伴生对象 def printPerson(person: Person) = { println(person.name) } } def main(args: Array[String]): Unit = { val person = new Person("lzs") //伴生类 Person.printPerson(person) //伴生对象 } }
13.apply方法
之前用过这种方式: 不用写: new + 类名 通过伴生方法的apply方法实现
// 创建一个Array对象 val a = Array(1,2,3,4) //定义apply方法 object 伴生对象名 { def apply(参数1:1类型,参数2:2的类型) = new 伴生类(参数1,参数2) }
object demo12 { class Person(var name:String ="",var age:Int=0) object Person{ def apply(name: String, age: Int): Person = new Person(name, age) } def main(args: Array[String]): Unit = { var person = Person("lzs",22) //不用写:new + 类名通过伴生方法的apply方法实现 println(person.name) println(person.age) } }
14.继承
通过继承来减少重复代码
scala和Java一样,使用extends关键字来实现继承
可以在子类中定义父类中没有的方法,或者重写父类的方法
类和单例对象都可以继承某个父类
语法 :
class | object 子类名 extends 父类名
object demo13 { class Person { var name: String = "" def getName()=this.name } class Student extends Person def main(args: Array[String]): Unit = { val student = new Student student.name="lzs" println(student.getName()) } }
15.单例对象继承
package cn.test01 //单例对象继承 object demo14 { class Person { var name: String = "" def getName() = this.name } object Student extends Person def main(args: Array[String]): Unit = { Student.name = "lzs" println(Student.getName()) } }
16.override 和 super
在子类中使用override可以来来重写父类的成员,可以使用super来引用父类
object demo15 { class Person{ val name= "" def getNmae()=this.name } class Student extends Person { //override覆写父类成员属性 override val name:String = "lzs" //override覆写父类成员方法 override def getNmae() = "hello"+super.getNmae() } def main(args: Array[String]): Unit = { val student = new Student println(student.getNmae()) } }
17.类型判断
islnstanceOf: 判断对象是否为指定类型
aslnstanceOf: 将对像转换为指定类型
object demo16 { class Person //定义person类 class Student extends Person //定义student类继承person类 def main(args: Array[String]): Unit = { //判断isInstanceOf val s:Person = new Student if (s.isInstanceOf[Student]){ //如果判断为true,把这个对象转成指定类 s.asInstanceOf[Person] } //打印结果 println(s.isInstanceOf[Person]) //true 模糊判断 父类引用指向子类也是true println(s.isInstanceOf[Student]) //true 模糊判断 父类引用指向子类也是true } }
18.判断类型
getClass 和 classOf
object demo17 { class Person class Student extends Person def main(args: Array[String]): Unit = { //父类指向子类引用 val p:Person = new Student //判断是否为Person类 println(p.getClass==classOf[Person]) //false new的谁就是谁 就为true //判断是否为Student类 println(p.getClass==classOf[Student]) //true new的谁就是谁 就为true } }
类(class)
特质(trait)
抽象类(abstract)===
19.抽象类
类的成员在类中是不完整的
-
方法没有方法体 就是(抽象方法)
-
关键字 : abstract 修饰就是抽象类
object demo18 { abstract class Shape{ def arae:Double } //创建正方形类继承Shape 实现他里边的抽象方法 class Square(var edge:Double/*边长*/)extends Shape { override def arae: Double = edge*edge } //定义一个长方形类继承Shape 实现他里边的抽象方法 class Rectangle(var length:Double /*长*/,var width:Double /*宽*/) extends Shape{ override def arae: Double = length*width } //定义一个圆形类继承Shape 实现他里边的抽象方法 class Cirle(var radius:Double/*半径*/) extends Shape{ override def arae: Double = Math.PI*(radius*radius) } def main(args: Array[String]): Unit = { //正方形 val square = new Square(10)//传参数 println(square.arae)//调方法打印 //长方形 val rectangle = new Rectangle(10,10)//传参数 println(rectangle.arae)//调方法打印 //圆 val cirle = new Cirle(10)//传参数 println(cirle.arae)//调方法打印 } }
20.抽象字段
-
变量没有初始化 就是(抽象字段)
语法:
abstract class 抽象类名{ var 字段:String }
//抽象字段 /* 1. 创建一个Person抽象类,它有一个String抽象字段WHO_AM_I 2. 创建一个Student类,继承自Person类,重写WHO_AM_I字段,初始化为学生 3. 创建一个Policeman类,继承自Person类,重写WHO_AM_I字段,初始化警察 4. 添加main方法,分别创建Student/Policeman的实例,然后分别打印WHO_AM_I */ object demo19 { abstract class Person { var WHO_AM_I: String //抽象字段 } class Student extends Person { override var WHO_AM_I: String = "学生" //实现父类抽象字段 } class Policeman extends Person { override var WHO_AM_I: String = "警察" //实现父类抽象字段 } def main(args: Array[String]): Unit = { val student = new Student //创建子类对象 println(student.WHO_AM_I) //打印 val policeman = new Policeman //创建子类对象 println(policeman.WHO_AM_I) //打印 } }
21.匿名内部类
是没有名称的子类
直接用来创建实例对象,
好处: 不需要定义子类,创建子类的对象调用方法,直接重回方法
语法:
val | var 变量名 = new 类 | 抽象类{ //重写方法 }
抽象类: 实现匿名内部类
//匿名内部类 object demo20 { abstract class Person{ def say:Unit } def main(args: Array[String]): Unit = { //没有名字的类, 匿名内部类 var p = new Person { //直接创建对象,覆写所有抽象成员(抽象字段,抽象方法) override def say: Unit = println("这是一个匿名内部类") } p.say } }
类: 实现匿名内部类
//匿名内部类 object demo20 { class Person{ def say = {"这是方法"} } def main(args: Array[String]): Unit = { val p = new Person { override def say: String = "这是一个匿名内部类" } println(p.say) } }
22.特质
Scala中没有Java接口 , 替代的概念的是特质
使用 trait 关键字
-
类继承只能继承一个超类 extends
-
一个类可以添加任意数量的特质 extends
-
注意 : scala不管是 类 , 抽象类 , 还是特质 , 都用 extends
//语法 : trait 特质名称{ //抽象字段 //抽象方法 }
class(类)继承单个trait (特质):
object demo01_TZ { trait logger{ //定义一个特质 def log(message:String) //定义一个抽象方法,传入参数为String } class ConsoleLogger extends logger { //继承这个特质,实现特质里的抽象方法 override def log(message: String): Unit = println(s"这是${message}"+"==把log方法实现后") } def main(args: Array[String]): Unit = { val logger = new ConsoleLogger logger.log("传入参数") } } //打印结果 : //这是参数==把log方法实现后
class(类)继承多个trait(特质) :
trait testTZ_01 {//第一个特质 def method01(sl:Int) //第一个特质的抽象方法 } trait testTZ_02 {//第二个特质 def method02(sl:Int) //第二个特质的抽象方法 } trait testTZ_03 {//第三个特质 def method03(sl:Int) //第三个特质的抽象方法 } /*==================================================*/ //创建类继承3个特质并实现特质里面的方法 class lei extends testTZ_01 with testTZ_02 with testTZ_03 { override def method01(sl: Int): Unit = println(s"这是第${sl}个特质方法的实现") override def method02(sl: Int): Unit =println(s"这是第${sl}个特质方法的实现") override def method03(sl: Int): Unit =println(s"这是第${sl}个特质方法的实现") } object demo02_TZ {//main方法 def main(args: Array[String]): Unit = { val lei = new lei lei.method01(1) lei.method02(2) lei.method03(3) } }
object(单例对象)继承trait(特质):
object demo03_TZ { //定义特质 trait logger { //抽象方法 def log(message: String) } //创建单例对象,继承特质 object ConsoleLogger extends logger { //是实现logger特质里的抽象方法 override def log(message: String): Unit = println(s"${message}==这是实现后的方法") } //定义main方法调用单例对象实现的方法 def main(args: Array[String]): Unit = { //单例对象相当于java静态,所以直接 [单例对象名.方法名] 调用就行 ConsoleLogger.log("传入的参数") }
trait(特质)里定义具体的方法
object demo04_TZ { //定义特质 trait Logger{ //在特质里定义具体方法 def log(c:String)=println(s"这是${c}==这是特质里的具体方法") } class UserService extends Logger { def add=log("参数") } /*===============================================================*/ //main方法入口 def main(args: Array[String]): Unit = { //玩了一下匿名内部类 val service = new UserService{ override def add: Unit = super.add } //调用匿名内部类的add方法 service.add } }
trait(特质)里定义具体的字段和抽象字段
import java.text.SimpleDateFormat import java.util.Date object demo05_TZ { //1.特质 trait Logger { //1.1抽象字段 var TYPE: String //1.2抽象方法 def log(cs: String) //1.3时间格式转换工具 val simpleDateFormat = new SimpleDateFormat("yyy-MM-dd HH:mm") def fangfa(date: Date) = simpleDateFormat.format(date) } //2.定义ConsoleLogger类继承特质 class ConsoleLogger extends Logger { //2.1实现抽象字段 override var TYPE: String = "现在时间是: " //2.2实现抽象方法 override def log(cs: String) = { var info = s"${TYPE} ${simpleDateFormat.format(new Date())}"+cs println(info) } } //3.main方法 def main(args: Array[String]): Unit = { // val logger = new ConsoleLogger logger.log("分") } }
对象混入trait(特质)
好处: 不用子类去继承父类,对对象进行赋能
object demo06_TZ { //定义特质 trait Logger { def log(cs: String) = println(cs) } //定义类,没有继承 class UserService def main(args: Array[String]): Unit = { //无需要继承,with关键字给对象赋能 val service = new UserService with Logger service.log("这是在对象中混入trait(特质)") } }
trait(特质)构造机制
构造的执行顺序
如果一个类继承了另一个类,又继承了N个特质,那么他的构造执行顺序如下 :
1.先执行父类(class)的构造,
2.执行特质(trait)的构造,
3.如果特质(trait)有父特质(trait),先执行父特质(trait)的构造
object demo07_TZ { //定义特质 trait Logger { println("2.执行Logger的构造") } trait MyLogger extends Logger { println("3.执行MyLogger的构造") } trait TimelLogger extends Logger { println("4.执行TimeLogger的构造") } class Person { println("1.执行Person的构造") } class Student extends Person with MyLogger with TimelLogger { println("5.执行Student的构造") } //main创建Student对象 def main(args: Array[String]): Unit = { new Student } } //打印结果为 //1.执行Person的构造 //2.执行Logger的构造 //3.执行MyLogger的构造 //4.执行TimeLogger的构造 //5.执行Student的构造 //印证了先执行父类(class)的构造,再执行特质(trait)的构造, //如果特质(trait)有父特质(trait),先执行父特质(trait)的构造
trait(特质)继承class(类)
object demo08_TZ { //1.定义类 class MyUtlis { //1.1定义方法,打印传入的参数 def printMsg(msg:String) =println(msg) } //2定义特质继承类 trait Logger extends MyUtlis { //2.1定义方法log,给父类方法传入参数"你好啊,lzs" def log(can:String)=printMsg(can +"lzs") } //3定义类继承特质 class Person extends Logger { //3.1定义方法sayHello给特质中的方法传入参数"你好啊," def sayHello = log("你好啊,") } //4定义main方法 def main(args: Array[String]): Unit = { //4.1创建Person对象 val person = new Person //4.2直接调用Person的sayHello就会直接打印参数 person.sayHello } }
样例类===
1.样例类语法
case class 样例类名(var|val 成员变量1:类型,成员变量2,类型,...) 当加了case修饰后 : 构造器的参数默认为val,(可以加var修饰,并不推荐) 自动在伴生对象中提供了apply方法,不用new,直接 类名 实例化 自动生成了toString , copy , hashCode , equals 方法
object demo09 { case class Person(name:String,age:Int) def main(args: Array[String]): Unit = { //自动在伴生对象中提供了apply方法,不用new,直接 类名 实例化 val person = Person("张三", 12) println(person) } }
2.可变成员变量
object demo10 { //可变成员变量,不加var默认为val,不可重新赋值 //定义样例类Person case class Person(var name:String,var age:Int) def main(args: Array[String]): Unit = { //直接类名创建对象,不用new val lzs = Person("lzs", 4) println(lzs) //打印结果: Person(lzs,45) lzs.age=22 println(lzs) //重新赋值后的打印结果: Person(lzs,22) } }
3.样例类方法
样例类给对象提供了apply , toString , copy , hashCode , equals 方法
当我们定义一个样例类 , 自动实现了apply , toString , copy , hashCode , equals 方法
apply方法 : 无需new,直接类名创建
object demo11_case { case class CasePerson(name:String,age:Int) def main(args: Array[String]): Unit = { val cases = CasePerson("LZS", 22) println(cases) } }
toString方法 :
object demo12_case { //样例类 case class CasePerson(name:String,age:Int) def main(args: Array[String]): Unit = { //直接类名创建,调用样例类的toString方法 val s = CasePerson("张三", 22).toString println(s) } }
equals方法:
//样例类 //equals object demo13_case { case class Person(name:String,age:Int) def main(args: Array[String]): Unit = { val lzs1 = Person("lzs", 22) val lzs2 = Person("lzs", 22) println(lzs1.equals(lzs2)) //结果为true } }
hashCod方法
//样例类 //hashCod object demo14_case { case class CasePerson(name:String,age:Int) def main(args: Array[String]): Unit = { val lzs01 = CasePerson("lzs", 22) val lzs02 = CasePerson("lzs", 22) println(lzs01.hashCode()) //打印结果 1251622611 println(lzs02.hashCode()) //打印结果 1251622611 /*====================================================================*/ var t1 = "重用" var t2 = "农丰" println(t1.hashCode()) //1187067 println(t2.hashCode()) //667668 } }
copy方法
//样例类 //copy方法 object demo15 { case class Person(name:String,age:Int) def main(args: Array[String]): Unit = { val lzs = Person("lzs", 22) val name = lzs.copy(age = 35) println(name) //打印结果 Person(lzs,35) } }
样例对象
1.用于定义枚举
2.用于没有任何参数的消息传递
语法: case object 样例对象名
1.使用case object 创建样例对象 2.样例对象是单例的 3.没有主构造器
定义枚举:
object demo16_mj { //定义sex表示性别枚举 trait Sex //定义样例对象实现Sex特质 case object Male extends Sex case object FeMale extends Sex //定义样例类 case class Person(name:String,sex:Sex) def main(args: Array[String]): Unit = { val zs = Person("张三",Male) println(zs) //打印结果 : Person(张三,Male) } }
简单模式 : match表达式
import scala.io.StdIn object demo17 extends App { println("请输入一个词") val str: String = StdIn.readLine()//键盘输入 var result = str match { case "hadoop" => "大数据分布式存储,分布式计算" case "zookeeper" =>"分布式协调服务框架" case "spark" => "分布式内存计算框架" case _ => "没结果" } println(result) }
匹配样例类
用模式匹配来匹配样例类,
可以快速获取样例类中的成员数据
import cn.test02.demo16_mj.Person object demo18_match { //创建两个样例类 case class Customer(name:String,age:Int) case class Order (id:String) //main方法 def main(args: Array[String]): Unit = { val lzs:Any = Customer("lzs", 22) val order:Any = Order("001") //使用macth case 表达式进行模式匹配 //获取样例类中的成员变量 lzs match{ case Person(name,age) =>println(s"${name},${age}") case Order(id)=>println(s"${id}") case _ =>println("啥也没有") } } }
Option类型: 自定义返回值
将来我们返回某些数据时,可以返回一个Option类型来替代。
当值为None是可以指定一个默认值
object demo19_Option { //定义方法,返回Option类型 def dvi(a: Double, b: Double): Option[Double] = { if (b != 0) { Some(a / b) //定义两个数相除 } else { None //有错误就返回 } } def main(args: Array[String]): Unit = { val option = dvi(5, 0) option match { case Some(a) => println(a) //没错就打印相除结果 case None => println("有错误") //分母就走自定义None } }
使用getOrElse方法,除零时,默认值为错误,与上边代码一样效果,更简便
object demo20_Option { def dvi (a:Int,b:Int): Option[Int] ={ if (b!=0){ Some (a/b) } else { None } } //使用getOrElse方法,当除零时,返回错误 def main(args: Array[String]): Unit = { val result = dvi(4,0).getOrElse("错误") println(result) } }
偏函数
在大括号内没有match的一组case语句就是一个偏函数
偏函数是PartialFunction[A, B]的一个实例
A代表输入参数类型
B代表返回结果类型
//f为一个输入类型为Int ,返回类型为String的偏函数 val f:PartialFunction[Int,String]={ case 1 => "yi" case 2 => "er" case 3 => "san" case _ => "*" } println(f)
//在大括号内没有match的一组case语句就是一个偏函数 val list = (1 to 10 ).toList val List2 = list.map({ case a if a>=1 && a<=3 => "[1~3]" case a if a>=4 && a<=5 => "[4~5]" case a if a>=8 => "[9-*]" }) println(List2)
异常处理
printStackTrace() : 打印错误的位置和信息
object demo22 { def main(args: Array[String]): Unit = { //使用try catch捕获 / 0异常 try{ val i = 4 /0 println("出现了这行,说明没有异常") }catch { case ex:ArrayIndexOutOfBoundsException => { println("如果发生了ArrayIndexOutOfBoundsException,会打印这句") ex.printStackTrace() //打印错误的位置和信息 } // case ex:Exception => { // println("如果发生了Exception,会打印这句") // ex.printStackTrace() //打印错误的位置和信息 // } } finally { println("无论如何都会打印这一行") } println("如果发生异常了,解决后,依然可以运行这行,没解决异常,走不到这") throw new Exception("不想理你.并向你扔了一个异常") } } // 把Exception注释掉后 // 1.没解决异常依然打印了: "无论如何都会打印这一行" // 2.没执行到: println("如果发生异常了,解决后,依然可以运行这行,没解决异常,走不到这")
object demo22 { def main(args: Array[String]): Unit = { //使用try catch捕获 / 0异常 try{ val i = 4 /0 println("出现了这行,说明没有异常") }catch { case ex:ArrayIndexOutOfBoundsException => { println("如果发生了ArrayIndexOutOfBoundsException,会打印这句") ex.printStackTrace() //打印错误的位置和信息 } case ex:Exception => { println("如果发生了Exception,会打印这句") ex.printStackTrace() //打印错误的位置和信息 } } finally { println("无论如何都会打印这一行") } println("如果发生异常了,解决后,依然可以运行这行,没解决异常,走不到这") throw new Exception("不想理你.并向你扔了一个异常") //手动抛出 } } //异常解决后,打印以下内容 /* 如果发生了Exception,会打印这句 无论如何都会打印这一行 如果发生异常了,解决后,依然可以运行这行,没解决异常,走不到这 Exception in thread "main" java.lang.Exception: 不想理你.并向你扔了一个异常 */
提取器
不是所有的类都可以进行 match case 模式匹配
要支持模式匹配,必须要实现一个提取器
-
类的伴生对象中的apply方法,可以用类名来快速构建一个对象。
-
伴生对象中还有一个unapply方法,与apply相反,unapply是将该类的对象拆解为一个个的元素
-
要实现一个类的提取器,只需要在该类的伴生对象中实现一个unapply方法即可
object demo23 { //定义Student类 class Student(var name: String, var age: Int) //定义伴生对象,覆写unapply方法 object Student { def unapply(arg: Student) = { if (arg != null) { Some((arg.age, arg.name)) } else { None } } } def main(args: Array[String]): Unit = { //使用match表达式进行模式匹配,提取类中的字段 val lzs = new Student("lzs", 22) lzs match { case Student(name,age)=>println(s"name=${name},age=${age}") } } }
泛型
object demo24 { //定义一个泛型类Pair泛型类 包含两个变量,类型不确定 case class Part[T](a:T,b:T) //main方法 def main(args: Array[String]): Unit = { //创建不同的泛型对象,并打印 val p1 = Part[Int](1, 2) //[Int]可以省略,因为scala可以自动判断 val p2 = Part("lzs", 2) val p3 = Part("lzs","Male") println(p1) println(p2) println(p3) } }
Actor====
-
-
定义class或object继承Actor特质
-
-
-
重写act方法
-
-
-
调用Actor的start方法执行Actor
-
object demo04 { //定义类继承Actor class myActor extends Actor{ //实现Actor的act方法打印1~10 override def act(): Unit = (1 to 10).foreach(println(_)) } //定义类继承Actor class myActor2 extends Actor{ //实现Actor的act方法打印10~20 override def act(): Unit = (10 to 20).foreach(println(_)) } def main(args: Array[String]): Unit = { //实例化并调用start方法 new myActor().start() //实例化并调用start方法 new myActor2().start() } }
import scala.actors.Actor //object继承Actor object demo05 { object MyActor01 extends Actor { override def act(): Unit = { for (i <- 1 to 10) { println(i) } } } object MyActor02 extends Actor { override def act(): Unit = { for (i <- 10 to 20) { println(i) } } } def main(args: Array[String]): Unit = { MyActor01.start() MyActor02.start() } }
高阶函数
-
作为值的函数
-
scala中函数就像数字,字符串一样,可以传入一个方法中
-
对算法封装将具体动作传递给方法
object demo06 { //main方法 def main(args: Array[String]): Unit = { //定义一个函数传给变量func val func= (x:Int)=>"*"*x //定义一个列表包含1~10 val i =(1 to 5).toList //函数传入集合对象方法map中 print(i.map(func)) } }
-
匿名函数
-
上边代码把函数(num:Int) => ""num 赋值给了变量写法啰嗦,
-
不需要函数赋值给变量,没有赋值给变量的函数就是匿名函数
object demo08 { def main(args: Array[String]): Unit = { //定义一个列表包含1~10 val list = (1 to 10).toList //定义函数不赋值给变量(就是一个匿名函数) println(list.map((i:Int)=>"*"*i)) //上述匿名函数简化如下 println(list.map(i=>"*"*i)) //上述匿名函数简化如下 println(list.map("*"*_)) } }
-
闭包
闭包就是一个函数
这个函数的返回值依赖于声明在函数外部的变量
可以访问不在当前作用域的一个函数
object demo09 { def main(args: Array[String]): Unit = { //函数外定义一个变量 val y = 10 val add = (x: Int) => { //函数内使用外部变量 : 闭包 x + y } } }
-
柯里化
是指将原先接受多个参数的方法转换为多个只有一个参数的参数列表的过程
柯里化方法(传入数字)
object demo11 { //1.编写一个方法calc_method(参数1,参数2),接收两个数字 def calc_method(c1:Int,c2:Int)={ 2*c1+c2 } //2.将这个方法用柯里化定义一次,定义两个括号参数列表的柯里化方法 def calc_method_curring(c1:Int)(c2:Int)={ 2*c1+c2 } //3.将柯里化的方法转换为函数,func1(参数1)(参数2) val func = calc_method_curring _ //main方法 def main(args: Array[String]): Unit = { //将其转换成只接受一个参数的函数func2(参数2) //4.在main方法中,给函数func的第一个参数传入具体对象,第二个参数不动 //5.调用函数func2(参数2),进行计算,打印结果 val func2=func(2) println(func2(3))//打印结果为 : 7 //6将func1中的参数列表传入不同的值对象,得到不同的func2,再次尝试 val func02=func(4) println(func02(2))//打印结果为 : 10 } }
柯里化方法(传入函数的)
object demo12 { //1===编写一个方法calc_mathod(参数1,参数2,参数3)接收三个参数, // 第一个参数接收一个函数对象,其余两个接收数字 def calc_mathod(fun_clac:(Int,Int)=>Int,c2:Int,c3:Int)={ fun_clac(c2,c3) //把后面两个参数传入这个函数 } //2===将上面的方法转换成接收两个括号参数列表的柯里化方法clac_samthod_curring(参数1)(参数2) // 第一个列表接收参数1函数,第二个参数列表接受两个数字 def calc_method_curring(fun_clac:(Int,Int)=>Int)(c2:Int,c3:Int)={ fun_clac(c2,c3) } def main(args: Array[String]): Unit = { //3===将柯里化方法转换成函数func1(参数1)(参数2) val func1 = calc_method_curring _ //4===在main方法中,给函数func1第一个参数传入具体对象 // 第二个参数不动,从而将其转换成只接收一个参数的func2(参数2) //func1((x,y)=>x*y) val func2=func1(_*_) //5.调用函数func2,打印结果 println(func2(3, 2)) //3*2 打印结果6 //6.将func1中的参数列表1传入不同的对象,得到func02,并打印 //func1((x,y)=>x-y) val func02= func1(_-_) println(func02(8,2)) //8-2 打印结果6 } }
隐式转换和隐式参数
隐式转换是指以implicit关键字声明的,带有单个参数的方法,
是被自动调用的,自动将某种类型转换成另外一种类型
object demo16 { //定义一个类包含File的变量和一个返回文本的方法 class Flietext(file:File){ //返回文本的方法read def read()=Source.fromFile(file).mkString } //定义Filetxet的伴生对象 object Flietext{ //返回它本身实例的方法 implicit def file01(file:File) = new Flietext(file) } def main(args: Array[String]): Unit = { //创建文件对象 val file = new File("./date/test.txt") import Flietext.file01 println(file.read()) } }
import java.io.File import scala.io.Source //自动导入隐式转换方法 //将隐式转换方法定义在main所在的object中 object demo17 { //定义一个类,其中有一个读取文本的方法 class RichFile(file:File){ def read() = Source.fromFile(file).mkString } //在这也行: //implicit def file(file:File)={new RichFile(file)} def main(args: Array[String]): Unit = { //在当前作用域中有隐式转换的方法,会自动导入 implicit def file(file:File)={new RichFile(file)} //加载文件路径 val file1 = new File("./date/test.txt") //file1也就有了read()方法 file1.read() } }
scala面试题
scala简介
scala是一个基于JVM的,
多范式语言(面向对象OOP,函数式编程),
简洁优雅(减少犯错),
可以使用Java的类库