一、Scala面向对象
1、Scala类
1.1定义类
1)在scala中,类并步用声明为public
2) 在scala文件中,文件名可以不用和类名一致
3)scala源文件可以包含多个类
1.2定义变量
1)用var修饰的变量既有getter又有setter
2)用val修饰的变量有getter没有setter
3)用private修饰的变量,只能在当前类的内部或伴生对象使用
4)使用private[this]修饰的变量,只能在当前类的内部使用,伴生对象不能访问
单列对象:用关键字object定义的对象,里面包括静态方法,静态属性,默认被private修饰
伴生对象:如果有同样一个类与该object名字一样,则称该object为该类的伴生对象
1.3定义构造器
注意:构造器会执行类定义所有语句
主构造器:
直接跟在类名的()中,()中的是参数列表
{}是主构造器要执行的代码
主构造器要被私有后,需要辅助构造器来创建对象
辅助构造器:
1.使用def关键字
2.使用this作为方法名
3.使用主构造器或其他构造器作为这个方法的第一句代码
4.辅助构造器中的参数是不能带val或var的
2、Scala对象
2.1单例对象
不需要new,用类名,方法名调用对象中的方法,用关键字object定义的对象
特点:
1、object里面的方法都是静态方法
2、object里面的字段都是静态字段
3、它本身就是一个单例(不需要去new)
2.2伴生对象
在scala的类中,与类名相同的单列对象叫做伴生对象。类和伴生对象之间可以相互访问私有的方法和属性
创建对象的三种方式
1、使用new调用主构造器
2、使用new调用辅助构造器(主构造器被私有了)
3、还可以使用对应的伴生对象中的apply方法去构造对象
要点:
1、在创建对象的时候,使用了new就表示 调用主构造器 或者辅助构造器
2、如果在构造对象的时候,没有使用new,其实是调用了这个类的伴生对象中的apply方法
unapply:析构函数,就是把一个对象拆成一堆零散的值返回
apply:构建函数,把一堆零散的值构建成一个对象返回
2.3抽象类
1、 如果一个类中包含抽象方法,那么这个类必须被定义为抽象类
2、如果子类extends抽象类,那么这个类依然是抽象类,要么实现父类中的所有抽象方法
3、如果子类重写父类中的非抽象方法,那么必须使用override关键字,如果要调用父类中的被重写的方法的话,适用super
4、如果子类实现一个抽象类,那么这个子类实现这个抽象类的所有方法
2.4特质
底层即使基于java抽象类实现的和scala中的抽象类一致:
可以定义抽象方法和属性也可以定义非抽象的方法和属性
当trait进行继承的时候:
1、如果其中有一个抽象类,那么抽象类必须在extends的后面,其他的特征在with的后面
2、如果要实现的有对各抽象和多个特质,那么当前这个语法不支持的情况下,只支持继承一个抽象类,和实现多个特质
3、也可以实现多个特质:
class EE extends AA with BB,CC,DD
结论:
extends的后面跟的可以是抽象类,也可以是trait ,with 后面跟的只能是trait了
scala可以多继承:
正常来说,java中的继承,就是至继承一个抽象类,但是在scala中,一个抽象类的定义,完全可以改变成trait,
本身scala是支持多实现trait的,所以只需要把多个抽象来都改写Trait就可以实现多继承了。
2.5模式匹配
出现的原因:改善java程序员编程switch....case.....的体验
1、可以匹配字符串
2、可以匹配类型
3、匹配数据,元组,集合
object Test {
def main(args: Array[String]) {
println(matchTest(3))
}
def matchTest(x: Int): String = x match {
case 1 => "one"
case 2 => "two"
case _ => "many"
}
}
偏函数:被包在花括号内没有match的一组case语句是一个偏函数,它是partialFunction[A,B]的一个实例,A代表参数类型,B代表返回类型,常用作输入模式匹配。
二、Scala高阶用法
1、高阶函数
主要有两种:
1)一种是将一个函数当做另一个函数的参数(即函数的参数是函数)
2)另一种是返回值是函数的函数(即函数的返回值是函数)
总结:
1)函数可以作为方法的返回值
2)函数可以作为方法的参数
3)函数也可以被转换为函数,特定场景下自动转换或者通过_手动转换
2、柯里化
1.定义:把接受多个参数的函数变成接受一个单一参数
2.作用:最大的作用,可以指定参数默认值
def sum4(x:Int)(y:Int = 10) = x + y
3、隐式参数和隐式转换(implicit)
1.作用
隐式的对类的方法进行增强,丰富现有类库的功能
2.例子
3.总结
1)隐式转换会首先从全局中寻找,寻找不到,才会使用隐式参数
2)隐式转换只能定义在object中
3)不能出现同类型的隐式转换,否则会报错
4.触发隐式转换的场景
1)当调用某个对象不存在的方法的时候会触发隐式转换
方法:把这个对象换成具有这个方法的对象
例子:Int调用to方法时,会转换为richInt
2)当调用某个方法的时候传入的参数的类型不匹配的时候
方法:把这个不匹配的类型转换成适应的类型
例子:参数定义为Int,而传入的类型为Doube
3)当存在视图边界的时候
4、闭包
1.定义:
闭包是一个函数,返回值依赖于声明在函数外的一个或多个变量
2.意义:
闭包就是用来解决,一个代码段去访问另一个方法或者函数的内部/局部变量
像这种运行时确定More类型及值的函数称为闭包,more是自由变量,在运行时其值和类型得以确定这是一个由开放(free)到封闭的过程,因此称为闭包。
5、泛型
1.用处
1)泛型类:指定类可以接受任意类型参数
2)泛型方法:指定方法可以接受任意参数
2.上界和下界
1)U >: T(下界的作用主要是保证类型安全)
这是类型下界的定义,也就是 U 必须是类型 T 的父类(或本身,自己也可以认为是自己的父类)。
2)S <: T
这是类型上界的定义,也就是 S 必须是类型 T 的子类(或本身,自己也可以认为是自己的子类)
3.视图界定(利用<%来实现)
跨越类继承层次结构是,可以使用视图界定来实现,其原理是通过隐式转换来实现
例子:int 实现comparable接口
原理: Int 类型此时会隐式转换为 RichInt 类,而RichInt 类属于 Comparable 继承层次结构。Int 类会隐式转换成 RichInt 类,RichInt 并不是直接实现 Comparable 口,而是通过 ScalaNumberProxy 类将 Comparable 中的方法继承过来。
4.协变和逆变
1.定义:
协变:当类型B是类型A的子类型是,则List[b]也可以认为是List[A]的子类型。也就是说被参数化类型的泛华方向与参数类型的方向是一致的,所有称为协变。
逆变:当B时是类型A的子类型,则Queue[A]反过来可以认为Queue[B]的值类型。