九、繼承
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
}
}