继承的概念

Scala中继承类的方式和Java一样,也是使用extends关键字:

1
2
3
class Employee extends Person{
var salary=1000
}

和Java一样,可在定义中给出子类需要而父类没有的字段和方法,或者重写父类的方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package lagou.cn.part05

class Person(name: String, age: Int){
println("这是父类Person!")
}

class Student(name: String, age: Int, var stuNo: String) extends Person(name, age){
println("这是子类Student!")
}

object ExtendsDemo {
def main(args: Array[String]): Unit = {
val student = new Student("jacky", 30, "1001")
// student.stuNo="1002"
// println(student.stuNo)
}
}

构造器执行顺序

Scala在继承的时候构造器的执行顺序:首先执行父类的主构造器,其次执行子类自身的主构造器。

类有一个主构造器和任意数量的辅助构造器,而每个辅助构造器都必须以对先前定义的辅助构造器或主构造器的调用开始。

子类的辅助构造器最终都会调用主构造器。只有主构造器可以调用父类的构造器。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//Person类
class Person(name:String,age:Int){
println("这是父类Person")
}

//Student继承Person类
class Student(name:String,age:Int,studentNo:String) extends Person(name,age){
println("这是子类Student")
}

object Demo{
def main(args: Array[String]): Unit = {
//下面的语句执行时会打印下列内容:
//这是父类Person
//这是子类Student
//也就是说,构造Student对象之前,首先会调用Person的主构造器
val student=new Student("john",18,"1024")
}
}

override方法重写

方法重写指的是当子类继承父类的时候,从父类继承过来的方法不能满足子类的需要,子类希望有自己的实现,这时需要对父类的方法进行重写,方法重写是实现多态的关键。

Scala中的方法重写同Java一样,也是利用override关键字标识重写父类的方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package lagou.cn.part05

class Programmer(name: String, age: Int) {
def coding(): Unit = {
println("我在写代码。。。")
}
}

class ScalaProgrammer(name: String, age: Int, workNo: String) extends Programmer(name, age) {
override def coding(): Unit = {
//调用父类的方法
super.coding()
//增加自己实现
println("我在写Scala代码。。。")
}
}

object OverrideDemo {
def main(args: Array[String]): Unit = {
val scalaProgrammer = new ScalaProgrammer("jacky", 30, "10010")
scalaProgrammer.coding()
}
}

需要强调一点:如果父类是抽象类,则override关键字可以不加。如果继承的父类是抽象类(假设抽象类为AbstractClass,子类为SubClass),在SubClass类中,AbstractClass对应的抽象方法如果没有实现的话,那SubClass也必须定义为抽象类,否则的话必须要有方法的实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//抽象的Person类
abstract class Person(name:String,age:Int){
def walk():Unit
}

//Student继承抽象Person类
class Student(name:String,age:Int,var studentNo:String) extends Person(name,age) {
//重写抽象类中的walk方法,可以不加override关键字
def walk():Unit={
println("walk like a elegant swan")
}
}

object Demo{
def main(args: Array[String]): Unit = {
val stu=new Student("john",18,"1024")
stu.walk()
}
}

类型检查与转换

要测试某个对象是否属于某个给定的类,可以用isInstanceOf方法。如果测试成功,可以用asInstanceOf方法进行类型转换

1
2
3
4
if(p.isInstanceOf[Employee]){
//s的类型转换为Employee
val s = p.asInstanceOf[Employee]
}

如果p指向的是Employee类及其子类的对象,则p.isInstanceOf[Employee]将会成功。

如果p是null,则p.isInstanceOf[Employee]将返回false,且p.asInstanceOf[Employee]将返回null。

如果p不是一个Employee,则p.asInstanceOf[Employee]将抛出异常。

如果想要测试p指向的是一个Employee对象但又不是其子类,可以用:

1
if(p.getClass == classOf[Employee])

classOf方法定义在scala.Preder对象中,因此会被自动引入。

不过,与类型检查和转换相比,模式匹配通常是更好的选择。

1
2
3
4
5
6
7
p match{
//将s作为Employee处理
case s: Employee => ...

//p不是Employee的情况
case _ => ....
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package lagou.cn.part05

class Person2

class Student2 extends Person2

object InstanceDemo {
def main(args: Array[String]): Unit = {
val p: Person2 = new Student2
var s: Student2 = null

//如果对象s是null,那么isInstanceOf会返回false
println(s.isInstanceOf[Student2])

if (p.isInstanceOf[Student2]) {
s = p.asInstanceOf[Student2]
}
println(s.isInstanceOf[Student2])

println(p.getClass == classOf[Person2])
println(p.getClass == classOf[Student2])

println("=====================================")
p match {
case s: Student2 => println("它是Student2类型的对象")
case _ => println("它啥也不是!")
}
}
}

结果:

1
2
3
4
5
6
false
true
false
true
=====================================
它是Student2类型的对象