九、继承
scala继承使用extends关键字
package classes
class Animals {
var name: String = ""
}
class Bear extends Animals {
def run = name + "在愉快的奔跑!"
}
object AnimalsDemo {
def main(args: Array[String]): Unit = {
val bear = new Bear
bear.name = "北极熊"
println(bear.run) // 北极熊在愉快的奔跑!
}
}
方法覆盖
覆盖父类中的方法,使用override关键字
如:
class Animals {
var name: String = ""
}
class Bear extends Animals {
def run = name + "在愉快的奔跑!"
// 覆盖toString方法
override def toString: String = name+"愉快的玩耍!"
}
object AnimalsDemo {
def main(args: Array[String]): Unit = {
val bear = new Bear
bear.name = "北极熊"
println(bear.run)
println(bear)
}
}
注意:
- final修饰的方法不能覆盖,类不能继承
- 调用父类中的方法,使用super.方法名
类型检查和转换
判断类型是否兼容,可以使用isInstanceOf
类型强转,可以使用asInstanceOf
val bear = new Bear
bear.name = "北极熊"
// println(bear.run)
// println(bear)
println(bear.isInstanceOf[Animals]) //true // 判断类型是否兼容
println(bear.asInstanceOf[Animals]) //classes.Bear@7d417077 // 类型转换
println(bear.getClass == classOf[Bear]) //true // 判断真实类型是否匹配
调用父类有参构造
类有一个主构器和任意数量的辅助构造器,而每个辅助构造器都必须以对先前定义的辅助构造器或主构造器的调用开始。子类的辅助构造器最终都会调用主构造器,只有主构造器可以调用超类的构造器。辅助构造器永远都不可能直接调用超类的构造器。在Scala的构造器中,你不能调用super(params)
import java.util.Date
class Person(var name: String)
// 表示:在创建子类对象时,首先调用父类的有参的主构造器
class Man(name: String, val birthday: Date) extends Person(name: String)
class Color
class Green extends Color()
重写字段
package classes.constructor
class Animals3 {
var name: String = ""
var count: Int = 0
val sex: Boolean = false
}
class Dog3 extends Animals3 {
name = "xh"
count = 1
override val sex: Boolean = true
}
object Animals3Demo {
def main(args: Array[String]): Unit = {
val a1: Animals3 = new Dog3()
println(a1.name) // "xh"
println(a1.count) // "1"
println(a1.sex) // "true"
}
}
覆写具体val 字段时,override 关键字是必不可少的,不过对于count 这个var 字段而言,则不然。这是因为修改val 字段意味着我们正在修改某一常量(val 字段)的初始化过程,这类“特殊”操作需要使用override 关键字。
抽象类
和Java一样,使用abstract关键字来标记不能被实例化的类
package classes.constructor
abstract class Student {
var name: String // 抽象字段,没有初始化
var sex: Boolean = false // 普通字段
def playGame(): String // 抽象方法 只有方法的声明,没有实现
}
class SmallStudent extends Student {
var name: String = "小王"
def playGame(): String = s"$name play 王者荣耀"
}
object StudentDemo {
def main(args: Array[String]): Unit = {
val s:Student = new SmallStudent
s.name="小刘"
println(s.playGame())
}
}
注意:
- 子类重写超类的抽象方法或者抽象字段时,可以省略override关键字
- 抽象类中的抽象字段被标记为var,生成的JAVA类并不带字段,自动产生抽象的getter和setter方法
- 抽象类中的抽象字段被标记为val,生成的JAVA类并不带字段,自动产生抽象的getter
匿名子类
类似Java的匿名内部类,可以通过包含带有定义或者重写代码块的方式创建一个匿名的子类
val s2 = new Student {
override def playGame(): String = s"$name play LOL"
override var name: String = "小张"
}
println(s2.playGame()) // 小张 play LOL
包可见性(访问修饰符)
在Scala里面就出现下面这几种类型:这里的省缺修饰符default,就是public。
- Class:类
- Companion:(伴生对象(相当于一个java里面的静态类),必须与所要陪伴的类放在同一个文件中)
- Subclass:子类
- Package:包
- World:同一文件
class Student {
// 缺省为public
var name: String = ""
val sex: Boolean = false
private var age: Int = 0
protected var birthday = new Date()
}
private限定 private修饰的属性只能对本类可以使用,对于伴生对象可见
object Student {
def apply(): Student = new Student()
def main(args: Array[String]): Unit = {
val s1 = Student()
// 伴生对象访问伴生类中的公开成员 ok
println(s1.sex)
// 伴生对象访问伴生类中的私有成员 ok
println(s1.age)
// 伴生对象访问伴生类中的受保护成员 ok
println(s1.birthday)
}
}
protected限定 protect修饰的属性对本类/伴生对象以及子类/子类的伴生对象可见
class SmallStudent extends Student {
}
object SmallStudent {
def apply: SmallStudent = new SmallStudent()
def main(args: Array[String]): Unit = {
val s1 = Student()
println(s1.birthday) //ok
println(s1.sex) //ok
println(s1.age) //error
}
}
private[this]
限定 如果严格限定属性可以操作范围仅仅限制在本类,去除伴生对象的可见性,可以添加this限定
class Student {
private[this] var id: Int = 1
}
object Student {
def apply(): Student = new Student()
def main(args: Array[String]): Unit = {
val s1 = Student()
// private[this] 修饰符仅限在伴生类中使用
println(s1.id) //error
}
}
protected[this]
限定如果严格限定属性可以操作范围仅仅限制在本类及其子类,去除伴生对象的可见性,可以添加protected限定
class SmallStudent extends Student {
override def toString: String = super.address // ok
}
object SmallStudent {
def apply: SmallStudent = new SmallStudent()
def main(args: Array[String]): Unit = {
val s1 = Student()
println(s1.birthday) //ok
println(s1.sex) //ok
println(s1.age) //error
println(s1) //error
}
}