七、scala面向對象-繼承

1、繼承java

一、extendses6

Scala中,讓子類繼承父類,與Java同樣,也是使用extends關鍵字 
繼承就表明,子類能夠從父類繼承父類的field和method;而後子類能夠在本身內部放入父類所沒有,
子類特有的field和method;使用繼承能夠有效複用代碼 
子類能夠覆蓋父類的field和method;可是若是父類用final修飾,field和method用final修飾,則該類是沒法被繼承的,
field和method是沒法被覆蓋的;


###
scala> :paste
// Entering paste mode (ctrl-D to finish)

class Person {
  private var name = "leo"
  def getName = name
}

class Student extends Person {
 private var score  = "A"
 def getScore = score
}

// Exiting paste mode, now interpreting.

defined class Person
defined class Student
warning: previously defined object Person is not a companion to class Person.
Companions must be defined together; you may wish to use :paste mode for this.

scala> val s = new Student
s: Student = Student@985696

scala> s.getName
res11: String = leo

scala> s.getScore
res12: String = A

scala> s.getName
res13: String = leo

scala> s.name
<console>:14: error: value name is not a member of Student
       s.name
         ^


二、override和superide

//Scala中,若是子類要覆蓋一個父類中的非抽象方法,則必須使用override關鍵字;

//override關鍵字能夠幫助咱們儘早地發現代碼裏的錯誤,好比:override修飾的父類方法的方法名咱們拼寫錯了;好比要覆蓋的父類方法的參數咱們寫錯了;等等

//此外,在子類覆蓋父類方法以後,若是咱們在子類中就是要調用父類的被覆蓋的方法呢?
   那就可使用super關鍵字,顯式地指定要調用父類的方法


###
scala> :paste
// Entering paste mode (ctrl-D to finish)

class Person {
  private var name = "leo"
  def getName = name
}

class Student extends Person {
  private var score = "A"
  def getScore = score
  override def getName = "Hi, I'm a student, my name is " + super.getName
}

// Exiting paste mode, now interpreting.

defined class Person
defined class Student
warning: previously defined object Person is not a companion to class Person.
Companions must be defined together; you may wish to use :paste mode for this.

scala> val s = new Student
s: Student = Student@618ad2aa

scala> s.getName
res15: String = Hi, I'm a student, my name is leo


三、override field函數

// Scala中,子類能夠覆蓋父類的val field,並且子類的val field還能夠覆蓋父類的val field的getter方法;只要在子類中使用override關鍵字便可

###
scala> :paste
// Entering paste mode (ctrl-D to finish)

class Person {
  val name: String = "Person"
  def age: Int = 0
}

class Student extends Person { 
  override val name: String  = "leo"
  override val age: Int = 30
}

// Exiting paste mode, now interpreting.

defined class Person
defined class Student
warning: previously defined object Person is not a companion to class Person.
Companions must be defined together; you may wish to use :paste mode for this.

scala> val p = new Person
p: Person = Person@71d9cb05

scala> p.name
res16: String = Person

scala> p.age
res17: Int = 0

scala> val s = new Student
s: Student = Student@1ac4ccad

scala> s.name
res18: String = leo

scala> s.age
res19: Int = 30


四、isInstanceOf和asInstanceOfthis

// 若是咱們建立了子類的對象,可是又將其賦予了父類類型的變量。則在後續的程序中,咱們又須要將父類類型的變量轉換爲子類類型的變量,應該如何作?
// 首先,須要使用isInstanceOf判斷對象是不是指定類的對象,若是是的話,則可使用asInstanceOf將對象轉換爲指定類型
// 注意,若是對象是null,則isInstanceOf必定返回false,asInstanceOf必定返回null
// 注意,若是沒有用isInstanceOf先判斷對象是否爲指定類的實例,就直接用asInstanceOf轉換,則可能會拋出異常



###
scala> class Person
defined class Person
warning: previously defined object Person is not a companion to class Person.
Companions must be defined together; you may wish to use :paste mode for this.

scala> class Student extends Person
defined class Student

scala> val p: Person = new Student
p: Person = Student@f324455

scala> var s: Student = null
s: Student = null

scala> if (p.isInstanceOf[Student]) s = p.asInstanceOf[Student]


五、getClass和classOfspa

// isInstanceOf只能判斷出對象是不是指定類以及其子類的對象,而不能精確判斷出,對象就是指定類的對象
// 若是要求精確地判斷對象就是指定類的對象,那麼就只能使用getClass和classOf了
// 對象.getClass能夠精確獲取對象的類,classOf[類]能夠精確獲取類,而後使用==操做符便可判斷


###
scala> class Person
defined class Person

scala> class Student extends Person
defined class Student

scala> val p: Person = new Student
p: Person = Student@77468bd9

scala> p.isInstanceOf[Person]
res0: Boolean = true

scala> p.getClass == classOf[Person]
res1: Boolean = false

scala> p.getClass == classOf[Student]
res2: Boolean = true


六、使用模式匹配進行類型判斷scala

// 可是在實際開發中,好比spark的源碼中,大量的地方都是使用了模式匹配的方式來進行類型的判斷,這種方式更加地簡潔明瞭,
並且代碼得可維護性和可擴展性也很是的高
// 使用模式匹配,功能性上來講,與isInstanceOf同樣,也是判斷主要是該類以及該類的子類的對象便可,不是精準判斷的



###
scala> class Person
defined class Person

scala> class Student extends Person
defined class Student

scala> val p: Person = new Student
p: Person = Student@192d3247

scala> p match {
     |   case per: Person => println("it's Person's object")
     |   case _ => println("unknown type")
     | }
it's Person's object


七、protectedcode

// 跟java同樣,scala中一樣可使用protected關鍵字來修飾field和method,這樣在子類中就不須要super關鍵字,直接就能夠訪問field和method
// 還可使用protected[this],則只能在當前子類對象中訪問父類的field和method,沒法經過其餘子類對象訪問父類的field和method


###
scala> :paste
// Entering paste mode (ctrl-D to finish)

class Person {
  protected var name: String = "leo"
}

class Student extends Person {
  def makeFriends(s: Student) {
    println("Hi, my name is " + name + ", your name is " + s.name)
  }
}

// Exiting paste mode, now interpreting.

defined class Person
defined class Student

scala> val s1 = new Student
s1: Student = Student@63355449

scala> val s2 = new Student
s2: Student = Student@1ab3a8c8

scala> s1.makeFriends(s2)
Hi, my name is leo, your name is leo




scala> :paste
// Entering paste mode (ctrl-D to finish)

class Person {
  protected[this] val name: String  = "leo"
}

class Student extends Person {
  def makeFriends(s: Student) {
    println("my name is " + name + ", your name is " + s.name)
  }
}

// Exiting paste mode, now interpreting.

<console>:22: error: value name is not a member of Student
           println("my name is " + name + ", your name is " + s.name)
                                                                ^


八、調用父類的constructor對象

// Scala中,每一個類能夠有一個主constructor和任意多個輔助constructor,而每一個輔助constructor的第一行都必須是調用其餘輔助constructor或者是主constructor;
所以子類的輔助constructor是必定不可能直接調用父類的constructor的
// 只能在子類的主constructor中調用父類的constructor,如下這種語法,就是經過子類的主構造函數來調用父類的構造函數
// 注意!若是是父類中接收的參數,好比name和age,子類中接收時,就不要用任何val或var來修飾了,不然會認爲是子類要覆蓋父類的field


###
scala> :paste
// Entering paste mode (ctrl-D to finish)

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.0)
  }
  def this(age: Int) {
    this("leo", age, 0)
  }
}

// Exiting paste mode, now interpreting.

defined class Person
defined class Student

scala> val s = new Student("leo", 30, 100)
s: Student = Student@783a467b

scala> s.name
res6: String = leo

scala> s.age
res7: Int = 30

scala> s.score
res8: Double = 100.0

scala> val s2 = new Student("leo")
s2: Student = Student@6f204a1a

scala> s2.name
res9: String = leo

scala> s2.age
res10: Int = 0

scala> val s3 = new Student(30)
s3: Student = Student@3224a577

scala> s3.name
res11: String = leo

scala> s3.age
res12: Int = 30

scala> s3.score
res13: Double = 0.0


九、匿名子類blog

// 在Scala中,匿名子類是很是常見,並且很是強大的。Spark的源碼中也大量使用了這種匿名子類。
// 匿名子類,也就是說,能夠定義一個類的沒有名稱的子類,並直接建立其對象,而後將對象的引用賦予一個變量。以後甚至能夠將該匿名子類的對象傳遞給其餘函數。


###
scala> :paste
// Entering paste mode (ctrl-D to finish)

class Person(protected val name: String) {
  def sayHello = "Hello, I'm " + name
}

val p = new Person("leo") {
  override def sayHello = "Hi, I'm " + name
}

def greeting(p: Person {def sayHello: String}) {
  println(p.sayHello)
}

// Exiting paste mode, now interpreting.

defined class Person
p: Person = $anon$1@3f270e0a
greeting: (p: Person{def sayHello: String})Unit

scala> greeting(p)
Hi, I'm leo


十、抽象類

// 若是在父類中,有某些方法沒法當即實現,而須要依賴不一樣的子來來覆蓋,重寫實現本身不一樣的方法實現。此時能夠將父類中的這些方法不給出具體的實現,
只有方法簽名,這種方法就是抽象方法。
// 而一個類中若是有一個抽象方法,那麼類就必須用abstract來聲明爲抽象類,此時抽象類是不能夠實例化的
// 在子類中覆蓋抽象類的抽象方法時,不須要使用override關鍵字



###
scala> :paste
// Entering paste mode (ctrl-D to finish)

abstract class Person(val name: String) {
  def sayHello: Unit
}

class Student(name: String) extends Person(name) {
  def sayHello: Unit = println("Hello, " + name)
}

// Exiting paste mode, now interpreting.

defined class Person
defined class Student

scala> val p = new Person
<console>:11: error: class Person is abstract; cannot be instantiated
       val p = new Person
               ^

scala> val s = new Student("leo")
s: Student = Student@368239c8

scala> s.sayHello
Hello, leo


十一、抽象field

// 若是在父類中,定義了field,可是沒有給出初始值,則此field爲抽象field
// 抽象field意味着,scala會根據本身的規則,爲var或val類型的field生成對應的getter和setter方法,可是父類中是沒有該field的
// 子類必須覆蓋field,以定義本身的具體field,而且覆蓋抽象field,不須要使用override關鍵字


###
scala> :paste
// Entering paste mode (ctrl-D to finish)

abstract class Person {
  val name: String
}

class Student extends Person {
  val name: String = "leo"
}

// Exiting paste mode, now interpreting.

defined class Person
defined class Student

scala> val s = new Student
s: Student = Student@1794d431

scala> s.name
res1: String = leo
相關文章
相關標籤/搜索