1.def 定义的是一个方法,用下划线可以转换为方法
2.window 换行符是/r/n linux /n
《逐云》
Scala 概述 2.11.8
- 优雅,速度快,融合hadoop生态圈。未来或许会替代MR,个人认为不可能。
- 最关键的就是 面向对象编程 和 面向函数编程
Windows 安装Scala编译器
- 下载scala-2.11.8.msi后点击下一步就可以了。
Linux安装Scala编译器
- 跟JDK一样,解压环境变量
Scala 基本语法
1. 变量声明
// object 类型代表 一个helloworld的实例
object helloworld {
// 在定义方法的时候,与java类型相反 变量名:数据类型
def main(args: Array[String]): Unit = {
//常量
val num = 100 ;
// 变量两种形式 ,
var str = "hell boy" ;
var str2: String = "ni bu zhidao shiqing "
}
}
2. 常用类型
- 与 java基本数据类型一致,重点是double无包装类型
3. 条件表达式
if else 的逻辑判断
// Unit 代表方法执行后的返回类型 def method_one(str: String): Unit = { val num = 3; // if else 逻辑判断 val num2 = { if (num > 5) 1 else if (num > 2) 2 else -1; } val num3 = if (num > 4) 1 else (); //输出 num3 equal () println("num2 equal " + num2); println("str equal " + str); println("num3 equal " + num3); } > 输出结果 num2 equal 2 > str equal rui > num3 equal ()
提示
默认返回的是常量值val unit = method_one(“rui”);
println(“method_one ” + unit) //输出结果 method_one (),() 就等于 unit
4. 块表达式
{…} 内部就被称为块表达式
val num2 = { if (num > 5) 1 else if (num > 2) 2 else -1; }
5.循环表达式
for 循环方式一
// 1 to 100 是一个区间 Range,每次返回的一个值都赋值给 i for (i <- 1 to 100) { println(i) }
for 循环遍历数组
// 数组代表一个区间 val arr = Array ('a', "b" , "av") ; for (i <- arr) { println(i) }
高级for循环
// 每个生成器都可以带一个条件,注意if前面 无 分号 // 双重 for循环 for (i <- 1 to 3 ; j <- 1 to 3 if i != j ) { // 满足条件进入循环体 print(j + " ") // 2 3 1 3 1 2 }
6.调用方法函数
Scala中的+ - * / %等操作符的作用与Java一样,位操作符 & | ^ >> <<也一样。只是有
一点特别的:这些操作符实际上是方法。通常来说不需要自定义返回值,系统会正常判断,但是对于递归函数必须要返回值例子 val str1 = num.+(str) val i = num.+(num2) println(str1) // 100hell boy println(i) // 1100 > 返回值类型可以自动推断出来 不需要重新定义
7.数组、映射、元组、集合
数组元素的添加,删除,打印
1. 定义数组 定义一个长度为10,类型为String的数组 val arr1 = new Array[String](10); println(arr1) //[Ljava.lang.String;@58651fd0输出的是hash值 2. 打印数组内容 //2. 将数组转换为数组缓冲就可以看到里面的内容 println(arr1.toBuffer) //ArrayBuffer(null, null, null, null, null, null, null, null, null, null) 3. 向数组中追加内容 //向数组中追加元素 arr3.+=("a"); println(arr3) 4. 向数组中添加数组,但是原来的长度,内容都不会变量 //向数组中追加数组 val arr4 = Array[Int](1,2); val arr5 = Array[Int](3,4,5); // ++ 集合不会改变arr4 val arr6= arr4.++(arr5) 5. 数组元素的插入或者移除 val array = Array(1,2,3,4); val arr1 = ArrayBuffer(1,2,3,4) // 前面是小标位置,后面的是元素内容 arr1.insert(0,-2,-3) println(arr1.toBuffer) arr1.remove(arr1.length) 6. 数组遍历 //初始化一个数组 val arr = Array(1,2,3,4,5,6,7,8) for(i <- arr) { println(i) } //读取的是小标反转 for(i<- (0 until arr.length).reverse){ print(arr(i)) } 7.数组过滤 val arr = Array(1, 2, 3, 4, 5, 6, 7, 8, 9) // yield 将原始数组转换为一个新的数组,原始数组不变 val arr1 = for( i <- arr if(i % 2 ==0)) yield i * 10; println(arr1.toBuffer) println(arr.toBuffer) // _ 就代表变量遍历出来的每一个元素 val a = arr1.filter(_ % 2 ==0).map(_* 100);print(a.toBuffer) println(a.sum) println(a.max) println(a.min) println(a.sorted)
映射关系map
val info = Map("name"->"tom","age"->"23","sex"->"nan") //有值返回值,没有值返回默认值 println(info("name"));println(info.getOrElse("pp",0)) 在映射关系中有个两个map类型,一个长度是否可变来区分 一个是immutable包下的Map,该Map中的内容不可变;另一个是mutable包下的Map,该Map中的内容可变
元组 也是一种映射关系,可以存储各种类型数据
// 定义一个元组 val t = ("123",3.131313,"Pp",1) // 元组的下标是从一个开始的 println(t._1) // 将对偶的集合转换为映射 val arr = Array(("p",11),("t",12)) arr.toMap // 拉杆操作 val rui = Array(10,20,30) val liu = Array("a","b") // 对应值进行捆绑 val liuguangrui = rui.zip(liu) val liuguangrui2 = rui.zipAll(liu,12,"ll") println(liuguangrui.toBuffer) println(liuguangrui2.toBuffer) 输出内容 ArrayBuffer((10,a), (20,b)) ArrayBuffer((10,a), (20,b), (30,ll))
8. 集合
Scala的集合有三大类:序列Seq、Set、映射Map,所有的集合都扩展自Iterable特质
在Scala中集合有可变(mutable)和不可变(immutable)两种类型,immutable类型的集合初始化后就不能改变了(注意与val修饰的变量进行区别)List集合
val left = List(1,2,3) val right = List(4,5,6) val uni = left ++ right println() println(uni.toArray.toBuffer) // println(left.++(right).toBuffer) //两个+ 代表加的集合 // println(left.++:(right).toBuffer) // println(left.+:("sdfdsf").toBuffer) //:就相当于头部 // println(left.:+("sdfdsf").toBuffer.head) //第一个元素 // println(left.:+("sdfdsf").toBuffer.tail) //除一个元素外的其他元素
Set集合
// 两个集合交集 val ints = set & set1 //在第一个集合基础上 去掉第二个集合重复元素 val ints1 = set -- set1 //并集 val ints2 = set ++ set1 // 返回第一个不同于第二个集合元素 val ints3 = set1 &~ set //set1.diff(set) // 大于6的元素 val i = set.count(_>=6) // 从角标0 开始 取代 2个元素 val ints4 = set.slice(0,2) val unit = set1.subsets(2).foreach(x=>println(x)) 定义一个可变长度 set1 += 1 ; println(set1.toBuffer) set1.add(2); println(set1.toBuffer) set1 ++=Set(1,4,5);println(set1)
Map集合
// 长度不可以改变,不可以去添加或者删除 val map1 = Map("rui" -> 12,"wen"->21) ; println(map1.toBuffer) val keys = map1.keys;println(keys.toBuffer) val set = map1.keySet;println(set.toBuffer) // 长度可以变化 val user =mutable.HashMap("zhangsan"->50,"lisi" -> 100) user +=("wangwu" -> 30);println(user.toBuffer) user("zhangsan") = 55;println(user.toBuffer) //修改键 user -=("zhangsan") //删除键 user += ("zhangsan" -> 60, "lisi" -> 50) //添加键 user.remove("zhangsan0") // 删除键 // 遍历map方法 for((x,y) <- user) println(x+" -> "+y) // for循环 for(x<- user.keys) println(x+" -> "+user(x)) //键集 获取值 user.foreach{case (x,y) => println(x+" -> "+y)} //foreach 循环遍历
类、对象、继承、特质
类
类型一
// 主构造器 会执行类中定义所有语句,方法解析不执行 class Person (val nameStr:String,val age : Int){ // val 修饰的变量,只有get方法 无set方法 val id = "9527".toInt val str: String = "rui" //类私有字段,只能在类的内部使用 private var name: String = "唐伯虎" //对象私有字段,Person类的方法只能访问到当前对象的字段 private[this] val pet = "小强" var gender = "nan" ; //get,set都有 //辅助构造器,第一行必须要调用主构造器 // def this(name : String,age :Int,gender:String){ // this(name,id); // this.gender = gender // } }
类型二
class Queen (val name : String ,prop : Array[String],private var age : Int=23) { println(prop.length) // 由于age被private修饰,隐藏 age , name 都等同于被private修饰 def description = name + " is " + age + " years old with " + prop.toBuffer } object Queen{ def main(args: Array[String]) { //私有的构造器,只有在其伴生对象中使用 val q = new Queen("itcast", Array("黑马", "博学谷"), 10) println(q.description) } }
对象 由于在scala中没有静态方法字段,因此通过object达到同静态方法字段同样的效率
伴生对象 1. 在一个文件中, 类名与object名字相同,彼此可以相互访问
// 通过object达到同静态方法字段同样的效率 class SingleDemo { def main(args: Array[String]): Unit = { val demo: SingleDemo = SessionFactory.getSession() println(demo) } } object SessionFactory{ //该部分相当于java中的静态块 var counts = 5 val sessions = new ArrayBuffer[SingleDemo]() while(counts > 0){ sessions += new SingleDemo counts -= 1 } //在object中的方法相当于java中的静态方法 def getSession(): SingleDemo ={ sessions.remove(0) } }
Scala中isInstanceOf 和 asInstanceOf 区别
is是先判断 q.isInstanceOf(a)q是a的一个实例,只能判断q是a子类或者其实体类
q.asInstanceOf(a)将q转为a,通常来说都是先判断后转
如果对象是 null,则 isInstanceOf 一定返回 false, asInstanceOf 一定返回 null;
//判断p是否为Person4类的实例
println(p.isInstanceOf[Person4])//true
//判断p的类型是否为Person4类
println(p.getClass == classOf[Person4])//false
//判断p的类型是否为Student4类
println(p.getClass == classOf[Student4])//true
可以向下面这样写
val p:Person5=new Student5
p match {
// 匹配是否为Person类或其子类
case per:Person5 => println("This is a Person5's Object!")
// 匹配所有剩余情况
case _ =>println("Unknown type!")
}
匿名内部类
//匿名内部类 class Person8(val name:String) { def sayHello="Hello ,I'm "+name } class GreetDemo{ def hell(person8 : Person8{ def sayHello : String }) ={ println(person8.sayHello) } } object GreetDemo { def main(args: Array[String]) { //创建Person8的匿名子类对象 val p=new Person8("tom") val g=new GreetDemo g.hell(p) } }
重写抽象类
// 抽象方法 abstract class Person9 (val name:String){ //必须指出返回类型,不然默认返回为Unit def sayHello:String def sayBye:String } // 在子类中覆盖抽象类的抽象方法时,可以不加override关键字; class Student9(name:String) extends Person9(name){ //必须指出返回类型,不然默认 def sayHello: String = "Hello,"+name def sayBye: String ="Bye,"+name } object Student9{ def main(args: Array[String]) { val s = new Student9("tom") println(s.sayHello) println(s.sayBye) } } //抽象类中 字段没有给出初始值的话,子类集成抽象类后需要复写 abstract class Person10 (val name:String){ //抽象fields val age:Int } class Student10(name: String) extends Person10(name) { val age: Int = 50 }
9. Trait 用法
- Trait 类似于 抽象类 或者接口 类与trait之间是继承的关系,trait与trait之间是with关系
- 继承 trait 获取的field直接被添加到子类中
- 子类调用父类的方法
- 必须覆盖抽象类中 field字段
9.1 实例对象中指定混入某个trait
trait LoggedTrait {
// 该方法为实现的具体方法
def log(msg: String) = {println("sdfdsf")}
}
trait MyLogger extends LoggedTrait{
// 覆盖 log() 方法
override def log(msg: String) = println("log: " + msg)
}
class PersonForMixTraitMethod(val name: String) extends LoggedTrait {
def sayHello = {
println("Hi, I'm " + this.name)
log("sayHello method is invoked!")
}
}
object PersonForMixTraitMethod{
def main(args: Array[String]) {
val tom= new PersonForMixTraitMethod("Tom").sayHello //结果为:Hi, I'm Tom sdfdsf
// 使用 with 关键字,指定混入MyLogger trait
val rose = new PersonForMixTraitMethod("Rose") with MyLogger
rose.sayHello
// 结果为: Hi, I'm Rose
// 结果为: log: sayHello method is invoked!
}
}
9.2 trait之间继承关系
- //1. 类与类之间 先走父类
- //2. trait之间先走父类,从左到右的顺序
//3. 最后走本类的苟泽
//1
class Person_One {println(“Person’s constructor!”)
}//2
trait Logger_One {
println(“Logger’s constructor!”)
}//3
trait MyLogger_One extends Logger_One {
println(“MyLogger’s constructor!”)
}
//4
trait TimeLogger_One extends Logger_One {
println(“TimeLogger’s contructor!”)
}
// 1. 类与类之间 先走父类
//2. trait之间先走父类,从左到右的顺序
//3. 最后走本类的苟泽//5
class Student_One extends Person_One with MyLogger_One with TimeLogger_One {
println(“Student’s constructor!”)
}
object exe_one {
def main(args: Array[String]): Unit = {
val student = new Student_One
//执行结果为:
// Person’s constructor!
// Logger’s constructor!
// MyLogger’s constructor!
// TimeLogger’s contructor!
// Student’s constructor!
}
}
1. 模式匹配和样例类
case匹配模式数据类型与内容匹配
val arr = Array("hadoop", "zookeeper", "spark") val name = arr(Random.nextInt(arr.length)) // 内容匹配 name match { case "hadoop" => println("大数据分布式存储和计算框架...") case "zookeeper" => println("大数据分布式协调服务框架...") case "spark" => println("大数据分布式内存计算框架...") case _ => println("我不认识你...") } val arr1 = Array("hello", 1, 2.0, CaseDemo01) val v = arr1(Random.nextInt(4)) // 类型匹配 v match { case x: Int => println("Int " + x) case y: Double if(y >= 0) => println("Double "+ y)// 匹配的时候还可以添加守卫条件 case z: String => println("String " + z) case _ => throw new Exception("not match exception") } // 集合匹配 val lst = List(3, -1) lst match { case 0 :: Nil => println("only 0") case x :: y :: Nil => println(s"x: $x y: $y") case 0 :: tail => println("0 ...") case _ => println("something else") } // 元组匹配 val tup = (2, 3, 7) tup match { case (1, x, y) => println(s"1, $x , $y") //输出格式,前面必须是s case (_, z, 5) => println(z) case _ => println("else") } //引用类型匹配 val arr = Array(CheckTimeOutTask, HeartBeat(12333), SubmitTask("0001", "task-0001")) arr(Random.nextInt(arr.length)) match { case SubmitTask(id, name) => { println(s"$id, $name") } case HeartBeat(time) => { println(time) } case CheckTimeOutTask => { println("check") } } //map类型匹配 val map = Map("a" -> 1, "b" -> 2) val v = map.get("b") match { case Some(i) => i case None => 0 } //PartialFunction[A, B] A代表参数类型 B代表返回值 def func1: PartialFunction[String, Int] = { case "one" => 1 case "two" => 2 case _ => -1 } 协变、逆变、非变总结 C[+T]:如果A是B的子类,那么C[A]是C[B]的子类。 C[-T]:如果A是B的子类,那么C[B]是C[A]的子类。 C[T]: 无论A和B是什么关系,C[A]和C[B]没有从属关系。
Scala中的上下界 (重点)
Scala的上下边界特性允许泛型类型是某个类的子类,或者是某个类的父类;
(1) U >: T
这是类型下界的定义,也就是U必须是类型T的父类(或本身,自己也可以认为是自己的父类)。
(2) S <: T
这是类型上界的定义,也就是S必须是类型T的子类(或本身,自己也可以认为是自己的子类)。