默认值:
var a:String = _ (是var,不是val,会报错。结果:null)
var b:Boolean = _ (false)
var d:Double = _ (0.0)
var i:Int =_ (0)
构造器/构造函数
主构造器是直接定义在类名后面,主构造器中的参数最终会被编译成字段/属性
(不带val或者var的参数其实是private的,自己调用没问题)
class ConstructorExtendsApp {
}
/**
* 构造器/构造函数(不带val或者var的参数其实是private的,自己调用没问题)
* 主构造器是直接定义在类名后面,主构造器中的参数最终会被编译成字段/属性
*/
//java 重载(自己的方法修改,重写:父方法的修改) (ps:override和overwrite的区别)
class Person(val name:String, val age:Int){
println("Person constructor enter...")
val school = "dfd"
var gender:String = _
def tt(): Unit ={
println("haha")
}
/**
* 附属构造器
* 语法: def this(....)
* 第一行代码:必须要调用已经存在的主构造器或者其他附属构造器
*/
def this(name:String, age:Int, gender:String){
this(name,age)
this.gender = gender
}
println("Person constructor leave...")
tt()
}
/**
* 子类构造方法触发之前要先触发其父类的构造方法
* 父类已有的字段就不需要使用val/var修饰(是不是私有的问题)
*/
class Student(name:String, age:Int, val major:String) extends Person(name,age){
println("Student constructor enter...")
override val school: String = "777"
//override def toString = "this is Student toString"
println("Student constructor leave...")
}
object ConstructorExtendsApp extends App{
// 继承了App类,就可以不需要main方法
// val person = new Person("dds",2)
// println(person.name + ":" + person.age)
// person.tt()
//
// val person2 = new Person("sdsds",23,"666")
// println(person2.gender)
val student = new Student("xiaow", 20, "huaxue")
println(student.toString)
println(student.school)
}
object类自带的方法有,hashCode,equals,clone(Creates and returns a copy of this object.),toString,notify,notifyAll,wait,finalize (这些面试可能问)
/**
* class名字和object名字相同
* class就叫做object的伴生类
* object就叫做class的伴生对象(调用object不需要new,相当于Java的静态类)
* Java中,单例模式指的是使用静态方法来调用私有参数,这样外界调用方法时不用实例化。
*/
class ObjectApp {
}
class ApplyTest{
def test(): Unit ={
println("class test")
}
def apply() ={
println("class apply....")
}
}
object ApplyTest{
println("object enter...")
def apply() ={
println("object apply....")
new ApplyTest
}
//等价于下面
//def apply(): ApplyTest = new ApplyTest()
var count = 0
def static(): Unit ={
println("object static...")
}
def countSum() {
count += 1
}
println("object leave...")
}
object Timer {
var count = 0
def countSum(): Long ={
count += 1
count
}
}
object ObjectApp extends App {
ApplyTest.static()
//相当于先实例化再执行,所以enter和leave先执行,在执行static()
// for (i<- 1 to 10){
// ApplyTest.countSum()
// }
// println(ApplyTest.count)
//
// val a = new ApplyTest()
// a.test()
//伴生对象后面加() ==> 其实调用的是伴生对象的apply的方法 <== 定义的
//优点是直接用就可以,不用new class了
val b = ApplyTest()
b.test()
println(b)
b()
// val c = new ApplyTest()
// println(c)
// c()
/**
* 类名()(类名加上一个括号) ==> object apply
* new出来的对象()(new出来的对象加上一个括号) ==> class apply
*/
val aa = new Array[String](5)
val bb = Array("hadoop","spark","hive")
val cc = scala.collection.mutable.ArrayBuffer[Int](3)
}
其实
val a = Array(“sds”,“sd”)使用的就是object的apply方法(没有new,而且Array后面有括号)
10.mkString变成字符串
集合
Array 定长
ArrayBuffer 变长
Nil 是一个空list
List 定长
ListBuffer 变长
scala> Nil
res8: scala.collection.immutable.Nil.type = List()
scala> val l = List(1,2,3,4,5)
l: List[Int] = List(1, 2, 3, 4, 5)
scala> l.head
res9: Int = 1
scala> l.tail
res10: List[Int] = List(2, 3, 4, 5)
scala> val l2 = 1 :: Nil
l2: List[Int] = List(1)
scala> val l3 = 2 :: l2
l3: List[Int] = List(2, 1)
同样对于ListBuffer来说,可以使用+=(后可接元组,也可是单个的值),++=(后接List),-=(减的是具体的值,而不是下标),–=(减的是具体的值)
toArray,toList等方法也可用
Set …和list差不多
Map
键值对,取值直接用key
定义:val a = Map(“asd”->10)
取值:a(“asd”)
如果定义的是HashMap(可变长里面的,map不知能不能用)
为空的话,取值的时候是会报错的,因为没有这个key,可以使用c.getOrElse(“asd”,-1)来取值。
def getOrElse[B1 >: B](key: A, default: => B1): B1 = get(key) match {
case Some(v) => v
case None => default
}
Some: final case class Some[+A](x: A) extends Option[A]
None: case object None extends Option[Nothing]
所以m.get(1)得到的是Option[Int],需要再加一个get或者getOrElse才行
m.get(1).get 或者 m.get(1).getOrElse(“null”)
map的迭代:
val m = scala.collection.mutable.HashMap[String,Int]()
m += ("a"->3,"b"->4)
for((key,value) <- m){
println(key + " : " + value)
}
//keySet是一个都是key的集合
for(key <- m.keySet){
println(key + " : " + m.getOrElse(key, 0))
}
for(value <- m.values){
println(value)
}
for((key,_) <- m){
println(key + " : " + m.getOrElse(key, 0))
}
接口 interface (Java中的)
Trait(Scala中的,和Java中类似)
模式匹配
java: swich case 根据不同的条件走不同的分支
只能匹配值
类型、Array、List.. case class
变量 match {
case 值 => 代码
case 值 => 代码
case 值 => 代码
....
case _ => 代码
}
def judgeGrade2(name:String, grade:String): Unit = {
grade match {
case "A"=>println("prefect")
case "B"=>println("good")
case "C"=>println("just so so")
case _ if name == "666" =>println(name + " you are a good boy")
case _ => println("12121212")
}
}
def greeting(list: List[String]): Unit ={
list match {
case "dove"::Nil => println("Hi: 德芙")
case x::y::Nil => println("Hi: " + x + " , " + y)
case "xiaoweiba"::tail => println("Hi: xiaoweiba and other friends")
case _ => println("Hi: all")
}
}
def greeting(array: Array[String]): Unit ={
array match {
//dove开头的且只有一个元素
case Array("dove") => println("Hi: 德芙")
//2个任意元素
case Array(x,y) => println("Hello:" + x + "," + y)
//xiaoweiba开头的任意多个元素
case Array("xiaoweiba", _*) => println("Hello: zhangsan and other")
//大于等于3个元素,且不以xiaoweiba开头
case _ => println("Hi: everybody")
}
}
//Any是一个顶层的数据类型
def matchType(obj:Any): Unit ={
obj match {
case x:Int => println("int")
case s:String => println("string")
case m:Map[_,_] => m.foreach(println)
case _ => println("other type")
}
}
之后的调用可以适用任何情况
异常处理(IO的步骤)
//IO常见处理步骤
try {
//1) open file
//2) use file
val i = 1/0
} catch {
case e:ArithmeticException => println("除数不能为0")
case e:Exception => println("错误的地方/原因为:" + e.getMessage)
} finally {
//io file(io的关闭)
println("finally")
}
case class(不用new就可以直接使用,在Spark SQL中用的比较多)
class Person
case class CTO(name:String, floor:String) extends Person
case class Employee(name:String, floor:String) extends Person
case class Other(name:String) extends Person
def judgeIdentify(person:Person): Unit ={
person match {
//可以直接 case 子类
case CTO(name,floor) => println("cto")
case Employee(name,floor)=>println("Employee")
case _ => println("Other")
}
}
//是个方法,可以调用
judgeIdentify(CTO("dove","3"))
judgeIdentify(Other("Other"))
高阶函数 *****
一个函数是可以赋值给一个常量的,不过赋值的时候函数名要加" _"或者"(_)"
def sayHello(name:String): Unit ={
println("Hello:" + name)
}
val sayHelloFunc = sayHello _
val sayHelloFunc = sayHello(_)
高阶函数map,reduce,fold…
val l = List(1,2,3,4,5,6,7,8)
//所有元素乘以2, map:把l里面的每个元素都做一个相同的操作1ll1
l.map((x:Int) => x*2)
//参数的类型推断机制,可以省略类型
l.map((x) => x*2)
l.map(x => x*2)
l.map(_*2)
//以上四个的结果相同
l.map(_*2).filter(_>8)//_ 代表每个元素,取大于8的
l.take(4)//取前四个
//reduce:对元素x和元素y进行处理,使用后面的方法(即x+y)进行处理,以此类推,最后结果是所有元素的和
l.reduce((x, y)=>x+y)
l.reduce(_ + _)//l.reduce(_ - _)
//打印出来就能看到详细内容
l.reduce((x,y) =>{
println(x + " , " + y)
x-y
})
//reduceLeft和reduce类似,reduceRight是从右往左减,第一步:(7-8),下一步:(6-(-1)) ...
l.max //8
l.min //1
l.sum //36
//求大于3的个数
l.count(x => x>3)
l.count(_>3)
val f = List(List(1,2),List(3,4),List(5,6))
f.flatten //这个是一个算子,把f里面的所有元素扁平化,结果List(1,2,3,4,5,6)
f.flatMap(_.map(_*2)) //等于map+flatten
匿名函数
(x:Int) => x+1(只有一个参数的话,括号可以省略,但是需要在外面加大括号)
{x:Int => x+1}
所以可以def add = (x:Int,y:Int) => x+y这样用
(x:Int) => x+1相当于y = f(x),x是入参,y是出参,对应的,x:Int是入参,x+1是出参
currying函数
//currying函数(柯里化)
def sum(a:Int, b:Int) = a+b //正常函数
def sum2(a:Int)(b:Int) = a+b
println(sum(1,2))
println(sum2(1)(2)) // Spark SQL UDF函数重点使用
偏函数 PartialFunction
val array = Array("111","222","333")
val name = array(Random.nextInt(array.length))
def sayChineseName(name:String):String = name match {
case "111" => "111"
case "222" => "222"
case _ => "333"
}
println(sayChineseName("222"))
//被包在花括号内没有match的一组case语句 ==> 偏函数
def sayChineseName2: PartialFunction[String, String] = {
case "111" => "111"
case "222" => "222"
case _ => "333"
}
println(sayChineseName2("222"))
字符串使用(源码里面用的比较多)
val name = "dove"
println("My name is : " + name)
println(s"My name is : $name")//带个s,因为里面用到了$
//多行字符串
val b =
"""
|zheshiyige
|duohang
|hallo
|haha
|333
""".stripMargin
println(b)
隐式转换
如何在一个已存在的类中添加一个方法(不许修改源代码/)
File中给我添加一个read方法
Java中可以使用动态代理,而Scala中可以使用隐式转换
implicit def file2RichFile(file:File) :RichFile = new RichFile(file)
val file = new File("C:\\Users\\sky\\Desktop/test.py")
val files = file.read()
//aa是一个迭代器
for (i <- files){
print(i)
}
class RichFile(val file: File){
def read() = Source.fromFile(file.getPath)
}
目的:隐式(偷偷摸摸)的对类的方法进行增强
核心:定义我们的隐式转换函数(implicit def xxxx)
object ImplictApp {
def main(args: Array[String]): Unit = {
//定义隐式转换即可,Scala会自动使用
implicit def man2superman(man: Man):SuperMan = new SuperMan(man.name)
val man = new Man("dove")
man.fly()
}
}
class Man(val name:String)
class SuperMan(val name:String){
def fly(): Unit ={
println(s"SuperMan $name fly")
}
}
一般都会把隐式转换放到一个单独的文件中,在需要的地方import
隐式参数
object ImplictParamApp extends App {
def testParam(implicit name:String): Unit ={
println(name)
}
testParam("aaa")
implicit val name = "gfgf"
testParam //会直接使用定义好的隐式参数
testParam("ssdsd")
//变量名随意,但不能有多个隐式参数,如果在main方法外面定义隐式参数,在里面的调用,也可以获取到值(作用域)。
implicit val s1 = "s1"
implicit val s2 = "s2"
// testParam
}