Scala面向对象
类
一个源文件中可以包含很多类,并且可以都是public级别
- getter 和 setter(classDemo -> Course )
- 在构造器中定义 var 属性,默认会生成get 和 set 方法
- 定义 val 属性 默认生成get 方法
- 构造函数(primary constructor & auxiliary constructor)
- 主构造器紧跟在类名后边,主构造器中参数会被编译成字段、主构造器会执行类中所有语句。
- 主构造器中参数如果不带 val 或者 var 相当于private[this],只能在类内部使用此参数
- 附属构造器用this 命名,附属构造器必须调用存在的构造器
- Scala 继承(extends)
继承的字段方法必须写override 关键字否则语法错误 - 重写父类方 方法(override def)
- 重写字段(override val , override var)
Scala包定义
重命名 import java.util.{HashMap => JavaHashMap}
访问权限
Scala的访问权限比Java的严格得多
-
私有成员:private的成员仅在包含了成员定义的类或对象内部可见(Java允许外部类访问其内部类 的私有成员)外部类无法访问内部类的私有成员
-
保护成员:protected成员只在成员的类的子类中可以被访问(对比java,还是比java 严格,哪怕该类在包外使用也不行; java 继承或者同包)
-
保护范围:private[x] protected[x] 相当于一种扩展,x类的所有子类都可访问
-
伴生类和伴生对象可以互相访问彼此的私有成员
object person 是class person 的伴生对象
class person 是object person的伴生类
Case Class
样例类的应用
-
基于值比较
同一个类的不同对象,当对象所有属性值相同时,则视为两对象相同
-
拷贝
copy()
在copy的同时还可以进行赋值
copy(age=3)
copy后进行比较,也是基于值的比较
-
进行模式匹配
caseOps(Student(19)) caseOps(Shared) //方法可以嵌套到main 函数里面 def caseOps(people:People) = people match {//定义caseOps方法,对输入参数people进行模式匹配 case Student(age) => println("age:" + age) case Worker(age,salary) => println("age:" +age + "salary" + salary) case Shared => println("nothing") }
抽象类
- 抽象类不能被实例化,除非将抽象方法实现
- 声明抽象方法不用abstract,不实现方法即可
- 父类可以声明抽象字段
- 子类实现父类抽象不用override
特质:trait*
- 为了解决多重继承问题
- 是可以有具体实现的接口(相比java中,接口里面的方法是不能实现的)
- 类可以通过with关键字实现任意数量的特质(第一混入特质用extends:当没有父类继承时候)在实例化对象的时候也可以with
- 特质无构造器参数
- 构造顺序:*
- 首先调用超类(父类)构造器混入类中
- 特质构造器在超类构造器之后、类构造器之前执行
- 每个特质中父特质先被构造
- 多个特质共有一个父特质,该父特质只构造一次
- 所有特质构造完毕,子类构造
- 特质的构造顺序从左向右跟线性化的顺序相反
- 特质也可以扩展类,这个类将自动成为所有混入该特质的超类
类的线性化
-
线性化是指为某个类的超类们指定线性顺序的过程
在Scala 里每个子类的这个顺序都有可能变化,并为继承树上的类重构造,这意味着一个共同父类的两个子类可能有不同的线性化,因此行为也可能不同。 -
线性化顺序与构造顺序相反
-
混入的顺序决定行为
越靠近右侧的特质越先起作用。当你调用带混入的类的方法时,最右侧特质的方法首先被调用。
如果那个方法调用了 super,它调用其左侧特质的方法。
sealed关键字
sealed 关键字主要有两个作用:
(1) 修饰的trait,class只能在当前文件里面被继承
(2) 用sealed修饰这样做的目的是告诉Scala 编译器在检查模式匹配的时候,让 Scala 知道这些case的所有情
scala就能够在编译的时候进行检查,看你写的代码是否有没有漏掉什么没case到,减少编程的错误。
(3)禁止类在文件外部被继承
(4)如果子类都明确的情况下,为了防止继承滥用,为抽象类添加sealed。
sealed abstract class People
case class Student(age: Int) extends People
case class Worker(age:Int,salary:Double) extends People
//能用于模式匹配,能序列化,actor 会用到
case object Shared extends People
object CaseClassDemo {
def main(args: Array[String]) {
caseOps(Student(19))
}
def caseOps(people:People) = people match {//定义caseOps方法,对输入参数people进行模式匹配
case Student(age) => println("age:" + age)
case Worker(age,salary) => println("age:" +age + "salary" + salary)
case Shared => println("nothing")
}
因为加了sealed(密封的)关键字,所以将caseOps进行修改
def caseOps(people:People) = people match {//定义caseOps方法,对输入参数people进行模式匹配
case Student(age) => println("age:" + age)
case Worker(age,salary) => println("age:" +age + "salary" + salary)
}
则会报错
Type
-
对类型进行重命名
type ConcreateType = Int//对类型的重命名 def main(args: Array[String]): Unit = { val param:ConcreateType = 1 println(param) }
-
定义抽象类型
型变
-
不变[A]
保持不变
-
协变[+A]
顺应继承关系,子类可以赋值给父类,父类型的值不能赋值给子类型的变量
-
逆变[-A]
父类可以赋值给子类
- 方法中的参数类型声明时必须符合逆变(或不变),以让子类方法可以接收更大的范围的参数(处理能力增 强);
- 而不能声明为协变,子类方法可接收的范围是父类中参数类型的子集(处理能力减弱)。
- 方法返回值声明必须符合协变或者不变。
观察者模式
定义了一种一对多的 依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态变化时,会通知所有的观察者对 象,使他们能够自动更新自己。
继承subject
subject中实现attach、detach、createHandle、notifyListeners方法
UpperBounds &LowerBounds
- 在Java泛型里表示某个类型是Test类型的子类型,使用extends关键字 <T extends Test> //或用通配符的形式: <? extends Test>
- upper bounds(中文为上限或上界),同样的意思在 scala 的写法为 [T <: Test] //或用通配符: [_ <: Test]
- 在Java泛型里表示某个类型是Test类型的父类型,使用super关键字 <T super Test> //或用通配符的形式: <? super Test>
- lower bounds(中文为下限或下界),同样的意思在 scala 的写法为:[T >: Test] //或用通配符: [_ >: Test]
意义在于自动根据继承关系决定返回类型?