scala當中的繼承


1、Scala中繼承(extends)的概念

  • Scala 中,讓子類繼承父類,與 Java 一樣,也是使用 extends 關鍵字;
  • 繼承就代表,子類可繼承父類的 field 和 method ,然后子類還可以在自己的內部實現父類沒有的,子類特有的 field 和method,使用繼承可以有效復用代碼;
  • 子類可以覆蓋父類的 field 和 method,但是如果父類用 final 修飾,或者 field 和 method 用 final 修飾,則該類是無法被繼承的,或者 field 和 method 是無法被覆蓋的。
  • private 修飾的 field 和 method 不可以被子類繼承,只能在類的內部使用;
  • field 必須要被定義成 val 的形式才能被繼承,並且還要使用 override 關鍵字。 因為 var 修飾的 field 是可變的,在子類中可直接引用被賦值,不需要被繼承;即 val 修飾的才允許被繼承,var 修飾的只允許被引用。繼承就是改變、覆蓋的意思。
  • Java 中的訪問控制權限,同樣適用於 Scala

  

類內部

本包

子類

外部包

public

protected

×

default

×

×

private

×

×

×

   

舉例說明:

    package com.starzy.extends_demo

    class Person {

      val name="super"

      def getName=this.name

    }

    class Student extends Person{

      //繼承加上關鍵字

      override

      val name="sub"

      //子類可以定義自己的fieldmethod

      val score="A"

      def getScore=this.score

    }

   

2、Scala中override 和 super 關鍵字

  • Scala中,如果子類要覆蓋父類中的一個非抽象方法,必須要使用 override 關鍵字;子類可以覆蓋父類的 val 修飾的field,只要在子類中使用 override 關鍵字即可。
  • override 關鍵字可以幫助開發者盡早的發現代碼中的錯誤,比如, override 修飾的父類方法的方法名拼寫錯誤。
  • 此外,在子類覆蓋父類方法后,如果在子類中要調用父類中被覆蓋的方法,則必須要使用 super 關鍵字,顯示的指出要調用的父類方法。

    舉例說明:

    class Person1 {

      private val name = "leo"

      val age=50

      def getName = this.name

    }

    class Student1 extends Person1{

      private val score = "A"

      //子類可以覆蓋父類的 val field,使用override關鍵字

      override

      val age=30

      def getScore = this.score

      //覆蓋父類非抽象方法,必須要使用 override 關鍵字

      //同時調用父類的方法,使用super關鍵字

      override def getName = "your name is " + super.getName

    }

   

3、Scala中isInstanceOf 和 asInstanceOf

如果實例化了子類的對象,但是將其賦予了父類類型的變量,在后續的過程中,又需要將父類類型的變量轉換為子類類型的變量,應該如何做?

  • 首先,需要使用 isInstanceOf 判斷對象是否為指定類的對象,如果是的話,則可以使用 asInstanceOf 將對象轉換為指定類型;
  • 注意: p.isInstanceOf[XX] 判斷 p 是否為 XX 對象的實例;p.asInstanceOf[XX] 把 p 轉換成 XX 對象的實例
  • 注意:如果沒有用 isInstanceOf 先判斷對象是否為指定類的實例,就直接用 asInstanceOf 轉換,則可能會拋出異常;
  • 注意:如果對象是 null,則 isInstanceOf 一定返回 false, asInstanceOf 一定返回 null;
  • Scala與Java類型檢查和轉換

       

Scala

Java

obj.isInstanceOf[C]

obj instanceof C

obj.asInstanceOf[C]

(C)obj

classOf[C]

C.class

   

舉例說明:

        class Person3 {}

        class Student3 extends Person3

        object Student3{

            def main (args: Array[String] ) {

            val p: Person3 = new Student3

            var s: Student3 = null

            //如果對象是 null,則 isInstanceOf 一定返回 false

            println (s.isInstanceOf[Student3])

            // 判斷 p 是否為 Student3 對象的實例

          if (p.isInstanceOf[Student3] ) {

            // p 轉換成 Student3 對象的實例

              s = p.asInstanceOf[Student3]

          }

          println (s.isInstanceOf[Student3] )

          }

   

}

   

4、Scala中getClass 和 classOf

  • isInstanceOf 只能判斷出對象是否為指定類以及其子類的對象,而不能精確的判斷出,對象就是指定類的對象;
  • 如果要求精確地判斷出對象就是指定類的對象,那么就只能使用 getClass 和 classOf 了;
  • p.getClass 可以精確地獲取對象的類,classOf[XX] 可以精確的獲取類,然后使用 == 操作符即可判斷;

    舉例說明:

    class Person4 {}

    class Student4 extends Person4

    object Student4{

      def main(args: Array[String]) {

        val p:Person4=new Student4

        //判斷p是否為Person4類的實例

        println(p.isInstanceOf[Person4])//true

        //判斷p的類型是否為Person4

        println(p.getClass == classOf[Person4])//false

        //判斷p的類型是否為Student4

        println(p.getClass == classOf[Student4])//true

      }

    }

   

5、Scala中使用模式匹配進行類型判斷

  • 在實際的開發中,比如 spark 源碼中,大量的地方使用了模式匹配的語法進行類型的判斷,這種方式更加地簡潔明了,而且代碼的可維護性和可擴展性也非常高;
  • 使用模式匹配,功能性上來說,與 isInstanceOf 的作用一樣,主要判斷是否為該類或其子類的對象即可,不是精准判斷
  • 等同於 Java 中的 switch case 語法;

    舉例說明:

    class Person5 {}

    class Student5 extends Person5

    object Student5{

      def main(args: Array[String]) {

        val p:Person5=new Student5

        p match {

          // 匹配是否為Person類或其子類對象

          case per:Person5 => println("This is a Person5's Object!")

          // 匹配所有剩余情況

          case _  =>println("Unknown type!")

        }

      }

   

}

   

6、Scala中protected

  • 跟 Java 一樣,Scala 中同樣可使用 protected 關鍵字來修飾 field 和 method。在子類中,可直接訪問父類的 field 和 method,而不需要使用 super 關鍵字;
  • 還可以使用 protected[this] 關鍵字, 訪問權限的保護范圍:只允許在當前子類中訪問父類的 field 和 method,不允許通過其他子類對象訪問父類的 field 和 method。

   

舉例說明:

    class Person6{

      protected var name:String="tom"

      protected[this] var hobby:String ="game"

      protected def sayBye=println("再見...")

    }

    class Student6 extends Person6{

      //父類使用protected 關鍵字來修飾 field可以直接訪問

      def  sayHello =println("Hello "+name)

      //父類使用protected 關鍵字來修飾method可以直接訪問

      def  sayByeBye=sayBye

      def makeFriends(s:Student6)={

        println("My hobby is "+hobby+", your hobby is UnKnown")

      }

    }

    object Student6{

      def main(args: Array[String]) {

        val s:Student6=new Student6

        s.sayHello

        s.makeFriends(s)

        s.sayByeBye

      }

    }

   

7、Scala中調用父類的constructor

  • Scala中,每個類都可以有一個主constructor和任意多個輔助constructor,而且每個輔助constructor的第一行都必須調用其他輔助constructor或者主constructor代碼;因此子類的輔助constructor是一定不可能直接調用父類的constructor的
  • 只能在子類的主constructor中調用父類的constructor。
  • 如果父類的構造函數已經定義過的 field,比如name和age,子類再使用時,就不要用 val 或 var 來修飾了,否則會被認為,子類要覆蓋父類的field,且要求一定要使用 override 關鍵字。

    舉例說明:

    class Person7(val name:String,val age:Int){

      var score :Double=0.0

      var address:String="beijing"

      def this(name:String,score:Double)={

        //每個輔助constructor的第一行都必須調用其他輔助constructor或者主constructor代碼

        //constructor代碼

          this(name,30)

          this.score=score

      }

      //其他輔助constructor

      def this(name:String,address:String)={

          this(name,100.0)

          this.address=address

      }

    }

    class Student7(name:String,score:Double) extends Person7(name,score)

   

8、Scala中抽象類

  • 如果在父類中,有某些方法無法立即實現,而需要依賴不同的子類來覆蓋,重寫實現不同的方法。此時,可以將父類中的這些方法編寫成只含有方法簽名,不含方法體的形式,這種形式就叫做抽象方法;
  • 一個類中,如果含有一個抽象方法或抽象field,就必須使用abstract將類聲明為抽象類,該類是不可以被實例化的;
  • 在子類中覆蓋抽象類的抽象方法時,可以不加override關鍵字;

    舉例說明:

    abstract class Person9(val name:String) {

      //必須指出返回類型,不然默認返回為Unit

      def sayHello:String

      def sayBye:String

    }

    class Student9(name:String) extends Person9(name){

      //必須指出返回類型,不然默認

      def sayHello: String = "Hello,"+name

      def sayBye: String ="Bye,"+name

    }

    object Student9{

      def main(args: Array[String]) {

        val s = new Student9("tom")

        println(s.sayHello)

        println(s.sayBye)

      }

    }

   

 9、Scala中抽象field

  • 如果在父類中,定義了field,但是沒有給出初始值,則此field為抽象field;

    舉例說明:

    abstract class Person10 (val name:String){

    //抽象fields

        val age:Int

    }

    class Student10(name: String) extends Person10(name) {

       val age: Int = 50

    }

   


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM