scala 面向對象之 繼承
scala
1.extends
Scala中,讓子類繼承父類,與Java一樣,也是使用extends關鍵字
繼承就代表,子類可以從父類繼承父類的field和method;然后子類可以在自己內部放入父類所沒有,子類特有的field和method;使用繼承可以有效復用代碼
class Person {private var name = "leo"def getName = name}class Student extends Person {private var score = "A"def getScore = score}
子類可以覆蓋父類的field和method;但是如果父類用final修飾,則該類是無法被繼承的,field和method用final修飾,field和method是無法被覆蓋的
final class Person { //final embellish class Person it not be extendsprivate var name = "leo"def getName = name}class Student extends Person { //errorprivate var score = "A"def getScore = score}
eg:
scala> final class Person { | private var name = "leo" | def getName = name | } defined class Person scala> class Student extends Person { | private var score = "A" | def getScore = score | } <console>:8: error: illegal inheritance from final class Person class Student extends Person {
override 父類final修飾的字段 方法
class Person {private var name = "leo"final val age = 10; //final embellish field age it not be override by child classdef getName = name}class Student extends Person {private var score = "A"def getScore = scoreoverride val age = 20 //erroroverride def getName = "my name is" + super.getName}
eg:
scala> class Person { | private var name = "leo" | final val age = 10; //final embellish field age it not be override by child class | def getName = name | } defined class Person scala> class Student extends Person { | private var score = "A" | def getScore = score | override val age = 20 //error | override def getName = "my name is" + super.getName | } <console>:11: error: overriding value age in class Person of type Int(10); value age cannot override final member override val age = 20 //error
2.isInstanceOf 和 asInstanceOf
如果我們創建了子類的對象,但是又將其賦予了父類類型的變量。則在后續的程序中,我們又需要將父類類型的變量轉換為子類類型的變量,應該如何做?
首先,需要使用isInstanceOf判斷對象是否是指定類的對象,如果是的話,則可以使用asInstanceOf將對象轉換為指定類型 注意,如果對象是null,則isInstanceOf一定返回false,asInstanceOf一定返回null 注意,如果沒有用isInstanceOf先判斷對象是否為指定類的實例,就直接用asInstanceOf轉換,則可能會拋出異常
class Personclass Student extends Personval p: Person = new Studentvar s: Student = null //note:isInstanceOf and asInstanceOf use[] instead of ()if (p.isInstanceOf[Student]) s = p.asInstanceOf[Student]
但,isInstanceOf只能判斷是否為某個類或者某個類的子類,無法精確判斷。
eg:
scala> print(p.isInstanceOf[Student]) true scala> print(p.isInstanceOf[Person]) true scala>
3.getClass 和 classOf
isInstanceOf只能判斷出對象是否是指定類以及其子類的對象,而不能精確判斷出,對象就是指定類的對象
如果要求精確地判斷對象就是指定類的對象,那么就只能使用getClass和classOf了
對象.getClass可以精確獲取對象的類,classOf[類]可以精確獲取類,然后使用==操作符即可判斷
class Personclass Student extends Personval p: Person = new Studentp.isInstanceOf[Person]p.getClass == classOf[Person]p.isInstanceOf[Student]p.getClass == classOf[Student]
eg:
scala> p.getClass == classOf[Person] res20: Boolean = false scala> p.getClass == classOf[Student] res21: Boolean = true
4.使用匹配模式來進行類型判斷
但是在實際開發中,比如spark的源碼中,大量的地方都是使用了模式匹配的方式來進行類型的判斷,這種方式更加地簡潔明了,而且代碼得可維護性和可擴展性也非常的高
使用模式匹配,功能性上來說,與isInstanceOf一樣,也是判斷主要是該類以及該類的子類的對象即可,不是精准判斷的
class Personclass Student extends Personval p: Person = new Studentp match {case per: Person => println("it's Person's object")case _ => println("unknown type")}
3.protected
跟java一樣,scala中同樣可以使用protected關鍵字來修飾field和method,這樣在子類中就不需要super關鍵字,直接就可以訪問非private修飾的field和method(非private修飾的field可以直接訪問)
還可以使用protected[this],則只能在當前子類對象中訪問父類的field和method,無法通過其他子類對象訪問父類的field和method
class Person {protected var name: String = "leo"protected[this] var hobby: String = "game"}class Student extends Person {def sayHello = println("Hello, " + name)def makeFriends(s: Student) { //this s is not be current instance objectprintln("my hobby is " + hobby + ", your hobby is " + s.hobby)// error}}
eg1: error
scala> class Person { | protected var name: String = "leo" | protected[this] var hobby: String = "game" | } defined class Person scala> class Student extends Person { | def sayHello = println("Hello, " + name) | def makeFriends(s: Student) { | println("my hobby is " + hobby + ", your hobby is " + s.hobby) | } | } <console>:15: error: value hobby is not a member of Student println("my hobby is " + hobby + ", your hobby is " + s.hobby)
eg2:
scala> class Person { | protected var name: String = "leo" | protected var hobby:String = "game" | } defined class Person scala> class Student extends Person { | def sayHello = println("Hello, " + name) | def makeFriends(s: Student) { //this s is not be current instance object | println("my hobby is " + hobby + ", your hobby is " + s.hobby) | } | } defined class Student
4.調用父類的constructor
Scala中,每個類可以有一個主constructor和任意多個輔助constructor,而每個輔助constructor的第一行都必須是調用其他輔助constructor或者是主constructor;因此子類的輔助constructor是一定不可能直接調用父類的constructor的
只能在子類的主constructor中調用父類的constructor,以下這種語法,就是通過子類的主構造函數來調用父類的構造函數
注意!如果是父類中接收的參數,比如name和age,子類中接收時,就不要用任何val或var來修飾了,否則會認為是子類要覆蓋父類的field
class Person(val name: String, val age: Int)class Student(name: String, age: Int, var score: Double) extends Person(name, age) {def this(name: String) {this(name, 0, 0)}def this(age: Int) {this("leo", age, 0)}}
5.匿名內部類
在Scala中,匿名子類是非常常見,而且非常強大的。Spark的源碼中也大量使用了這種匿名子類。
匿名子類,也就是說,可以定義一個類的沒有名稱的子類,並直接創建其對象,然后將對象的引用賦予一個變量。之后甚至可以將該匿名子類的對象傳遞給其他函數。
class Person(protected val name: String) {def sayHello = "Hello, I'm " + name}val p = new Person("leo") {//p is a anonymity child class's objectoverride def sayHello = "Hi, I'm " + name}def greeting(p: Person { def sayHello: String }) {println(p.sayHello)}greeting(p)//use anonymity class's object as a method parameter
6.抽象類 abstract class and abstract field
如果在父類中,有某些方法無法立即實現,而需要依賴不同的子類來覆蓋,重寫實現自己不同的方法實現。此時可以將父類中的這些方法不給出具體的實現,只有方法簽名,這種方法就是抽象方法。
而一個類中如果有一個抽象方法,那么類就必須用abstract來聲明為抽象類,此時抽象類是不可以實例化的
在子類中覆蓋抽象類的抽象方法時,不需要使用override關鍵字
abstract class Person(val name: String) {def sayHello: Unit}class Student(name: String) extends Person(name) {def sayHello: Unit = println("Hello, " + name)}
如果在父類中,定義了field,但是沒有給出初始值,則此field為抽象field
抽象field意味着,scala會根據自己的規則,為var或val類型的field生成對應的getter和setter方法,但是父類中是沒有該field的
子類必須覆蓋field,以定義自己的具體field,並且覆蓋抽象field,不需要使用override關鍵字
abstract class Person {val name: String}class Student extends Person {val name: String = "leo"}
