-
类(class)
-
抽象类(abstract class)
-
-
特质(trait)
-
样例类(case class)
——————————————————————————————————
SCALA高级1、类Class2、继承&重写方法3、抽象类4、单例对象!!!!单例对象就是java中全是static和final的一种类!!!5、伴生5、特质trait(接口)6、混入特质(mix in trait)7、可替换混入8、选择结构9、样例类(case class) 重点10、模式匹配 match 重点11、提取器对象Object 重点12、泛型13、型变(泛型) 14、内部类15、正则 重点16、集成JAVA API
——————————————————————————————————
1、类Class
-
没有静态成员和方法
-
默认构造器就是定义类的的所有语句!!!
-
辅助构造器在主构造器其中,因为主构造器就是类的定义语句
-
辅助构造器第一句必须调用其它构造器
//主构造器执行类定义中的所有语句
class Point(var xc: Int, var yc: Int) {
var x: Int = xc //成员变量
var y: Int = yc //可以不写,直接使用xc|yc
//辅助构造器
def this() ={
this(0, 0) //第一句必须调用其他构造器
}
//成员方法
def move(dx: Int, dy: Int) ={
x = x + dx
y = y + dy
}
}
var p=new Point()
p=new Point(12,11)
2、继承&重写方法
-
extends实现类的继承
-
子类重写父类方法必须用override关键字声明
class WhitePoint() extends Point{
var color="white"
override def move(dx:Int,dy:Int)={
x=x+dx
y=y+dx
println(color+"chesse move to:"+x+","+y)
}
}
3、抽象类
-
抽象类可包含抽象方法
-
抽象类无法实例化
-
使用"abstract"关键字修饰
-
子类重写抽象方法时,override可选
abstract class Shape{
def draw():Unit
}
class Square extends Shape{
//省略构造器
//抽象方法的重写,override可省略
override def draw:Unit={
println("draw a square")
}
//省略构造器
var shape=new Square //多态,指向子类的父类引用
shape.draw //无参方法,省略()
}
4、单例对象
-
Scala的类中无法定义静态成员,即无static关键字。
-
没有构造器,所有不能有参数
-
使用object关键字定义单例对象,像Java一样表达类的静态成员变量、成员方法与静态代码块
-
单例成员相当于JAVA中类的单例模式(印证于其转换为class后全都加上了static)
-
第一次运行时执行所有代码,之后调用只能取值或函数
-
main()方法必须定义在单例对象中
-
单例对象与同名类定义在同一文件中时形成绑定关系(伴生类)
!!!!单例对象就是java中全是static和final的一种类!!!
object Blah {
println("Blah initializing...")
def sum(l: List[Int]): Int = l.sum
}
test.Blah.sum(List[Int](1, 2, 3, 4, 5))
5、伴生
-
单例对象与同名 类 定义在同一文件中时形成伴生绑定关系
-
伴生类与伴生对象可相互访问各自私有的成员(单例对象通过apply函数生成实例才可以访问类的成员,此时生成的就是一般的java类)
-
伴生对象可为伴生类增加静态成员
!!伴生就是java中的一般类,既有静态方法和成员又有普通方法和成员!!!
通过aplly方法和unapply方法实现两者的耦合,apply方法又提供了省略new的语法糖,使用感觉更像是一体的了
//单例对象通过apply方法返回一个伴生类的实例
//apply方法是关键字方法,默认返回同名类的new实例
//单例对象.apply()等价于 单例对象()
class Student(n: String, a: Int) {
private var name = n //私有变量,伴生对象可以访问
private var age = a
}
//伴生对象
object Student {
def apply(n: String, a: Int): Student = new Student(n, a)
def main(args: Array[String]): Unit = {
val stu=Student("Jason",9)
//通过伴生对象的apply()方法创建实例,省略了创建类实例时候的new Student()的new
println(stu.name)
}
}
5、特质trait(接口)
-
特质用于在类之间共享程序接口和字段,类似Java接口
-
特质是字段和方法的集合,可以提供字段和方法实现(!!!!可以实现!!!)
-
类和单例对象都可以扩展特质(extends)
-
特质不能被实例化,因此没有构造参数,类似Java接口
-
特质使用“trait”关键字定义
-
实现|覆盖特质中的方法使用“override“关键字,变量常量也是一样的
demo实例
//大部分性质与java中的接口是类似的
//唯一不同在于trait可以实现函数或者定义变量
trait Pet{
val name:String
def cry():Unit
}
class Dog(val name: String) extends Pet{
override def cry()=println("wow ...")
}
val dog = new Dog("Harry")
val animals = ArrayBuffer.empty[Pet]
animals.append(dog) //多态
animals.foreach(pet => {println(pet.name);pet.cry()}) //子类的方法
6、混入特质(mix in trait)
多重继承(trait):一个类只能有一个父类,但是可以继承多个trait
(想想trait和java接口的关系,但是trait可以实现方法和变量,所以用的也是extends关键字,称之为混入!)
-
既然用的是extends那么instanceof trait必然是true
-
类的混入时构造顺序从左向右,同一父类只会被构造一次
abstract class A {
val message: String
}
class B extends A {
val message = "I'm an instance of class B"
}
trait C extends A {
def loudMessage = message.toUpperCase()
}
class D extends B with C //静态混入
val d = new D
println(d.messge) // I'm an instance of class B
println(d.loudMessage) // I'M AN INSTANCE OF CLASS B
7、可替换混入
-
可替换的trait特性,一次定义,多种混入组合(必须是子类trait)
-
OTS:(继承也可以多态啦啦啦啦)
//类必须有声明从那个特质映射 class Drawing{ self:Shape=> //Shape是特质名,self指自身 //这句话声明将Shape特质的结构映射到本类 //既不继承也不实现,但可以提前编写调用trait的方法和变量的语句 //至于这些方法具体的实现,由使用时动态混入的特质决定(多态) //目的:trait的多态混入。 def start():Unit=draw() def stop():Unit=draw() } trait Shape {//父trait def draw(): Unit } trait Square extends Shape {//子trait def draw(): Unit = println("draw a square") } trait Triangle extends Shape {//子trait def draw(): Unit = println("draw a triangle") } //动态混入 (new Drawing() with Square).start() (new Drawing() with Triangle).start()
8、选择结构
1、Try
解决函数可能会判处异常的问题,成功则返回值,失败则如何
返回类型:
-
Success
-
Failure
2、Either
解决返回值不确定的问题,可以有两种返回值
返回类型:
-
Left:
-
Right:
3、Option
解决空指针问题
返回类型:
-
Some
-
None
9、样例类(case class) 重点
-
主要用于模式匹配match
-
常用于描述不可变的值的对象,数据完全依赖构造参数
-
构造参数默认为val常量,因此样例类默认不可变,通过模式匹配可分解出数值
-
只关心类中的值而不在意函数方法,类似javabean
-
自动创建伴生对象
-
自动实现方法toString|equals|copy
-
关键方法:
-
apply
-
unapply
-
-
两个样例类“==”操作时,通过按值比较而不是按引用
与class的区别:
如果一个类内部存在计算和其他复杂的行为,那它应该是class
10、模式匹配 match 重点
!!!模式允许任何类型!!!
-
基本模式匹配
//基本模式匹配 def matchTest(x: Int): String = x match { case 1 => "one" case 2 => "two" case _ => "many" } matchTest(3) // many matchTest(1) // one
-
模式守卫匹配
//模式守卫(在模式后面加上if 条件) def matchTest2(x: Int): String = x match { case i if i==1 => "one" case i if i==2 => "two" case _ => "many" } matchTest2(3) // many matchTest2(1) // one
-
仅类型匹配
//仅匹配类型 def matchTest3(x: Any): String = x match { case x:Int => "Int" case x:String => "String" case _ => "Any" } matchTest3(3.0) // Any matchTest3(1) // Int
-
样例类的组合匹配
//样例类的模式匹配 case class Student(_name:String,_age:Int) { var name=_name var age=_age } def matchTest4(x: Student)= x match { case Student(name,19) => println(name) case Student("Tom",age) => println(age) case Student(name,age) => println(name,age) case _ => println("no matches") } matchTest4(Student("Jason",19)) matchTest4(Student("Tom",20)) matchTest4(Student("Jimmy",20))
11、提取器对象Object 重点
-
对应样例类case class,相当于自定义的case class
-
单例对象中指定unapply()方法时,称为提取器对象(Extractor Objects)
-
unapply()方法接受一个实例对象,返回最初创建它所用的参数
-
unapply()相当于数学中的反函数,根据映射结果反转映射关系求原数据
class Student(_name:String,_age:Int) { var name=_name var age=_age } object Student{ def apply(name: String, age: Int): Student = new Student(name, age) def unapply(arg: Student): Option[(String, Int)] ={ if(arg==null) None else Some(arg.name,arg.age) } def matchTest(x:Student)=x match { case Student(name,age) if age<=20 => println("young man") //自动调用unaplly方法,返回的是个Option类 //apply是根据参数new类,很容易推理出unapply是根据对象获取参数 case Student(name,age) if age>20 => println("old man") } matchTest(Student("Jason",19)) //res0:young man
12、泛型
-
泛型类
-
泛型函数
-
基本与java相同
13、型变(泛型)
-
协变
Class demo[+T] {} //+表示的应该是同向型变 class b {} class a extends b{} //demo[a]是demo[b]的子类型,称之为协变
-
逆变
//与协变相反 class demo[-T]{} //反向型变 //demo[a]是deme[b]的父类
-
类型边界
class demo[T<:A] //泛型限定为类型A的子类,上界 class demo[T>:A] //泛型新丁为类型A的父类,下界 //编译期间检查,IDE不一定检查
14、内部类
-
与java内部类基本类似,但有很一点很不同:
-
scala的内部类是绑定到类的实例对象而不是类上
-
因此同类的不同的实例对象的内部类被认为是不同的类
-
可以认为内部类的类名是 实例hash+内部类名
-
15、正则 重点
-
r插值,保留原字符串不转义(用于保留正则字符中的转义)
r"wds" //w不会被scala转义成其他字符
-
s插值,字符串中可以使用$引用变量
s"$JAVA_HOME" //输出的是/opt/jdk
-
"str".r 将任何一个字符串转换为Regex类的实例对象
-
API
-
都是regex类的方法
//findAllMatchIn() 返回所有的匹配结果(Interator【Match】) val regex="abc".r regex.findAllMatchIn("abc@qq.com").foreach( x=>{ println(x.group(0),x.toString()) } ) //findFirstMatchIn() 返回第一个结果,返回类型是Option[Match] print(regex.findFirstMatchIn("abc@qq.com").getOrElse("not matched")) //findAllIn() 返回所有匹配的结果(Interator【String】) regex.findAllIn("abc@qq.com1huyang@cc.com").foreach(x=>{println(x)}) //最后一个是空
-
-
Regex类的模式匹配
val date = """(dddd)-(dd)-(dd)""".r "2014-05-23" match { case date(_*) => println("It is a date") } "2014-05-23" match { case date(year, _*) => println("The year of the date is " + year) } "2014-05-23" match { case date(year, month, day) => println(year,month,day) } //此处regex就是个自定义的extractor提取器,返回的是regex的构造参数即各个组的值 //g1,g2是str中的()分组
-
分组demo
//方式一 ,不推荐,太多了 case class Log(level:String,date:String,uri:String) object Father{ def main(args: Array[String]): Unit = { val log= """ |INFO 2016-07-25 requestURI:/c?app=0&p=1&did=18005472&industry=469&adid=31 |INFO 2016-07-25 requestURI:/c?app=0&p=2&did=18005472&industry=469&adid=31 |ERROR 2016-07-25 requestURI:/c?app=0&p=1&did=18005472&industry=469&adid=32 """.stripMargin val pattern="(?<level>\w+)\s(?<date>\d{4}-\d{2}-\d{2})\s[^:]+:(?<uri>.+)".r("level","date","uri") var logs:ListBuffer[Log]=ListBuffer[Log]() pattern.findAllMatchIn(log).foreach(x=>{ logs+=Log(x.group("level"),x.group("date"),x.group("uri")) }) logs.foreach(x=>{ println(x.level,x.date,x.uri) }) } } //方式二,推荐 pattern.findAllMatchIn(log).map(x=>{ Log(x.group("level"),x.group("date"),x.group("uri")) }).foreach(x=>{ logs.append(x) })
16、集成JAVA API
-
Scala无缝集成JavaAP
import java.text.SimpleDateFormat import java.util.{Calendar, Date} val dateFmt = "yyyy-MM-dd" def today(): String = { val date = new Date val sdf = new SimpleDateFormat(dateFmt) sdf.format(date) }