1. 程式人生 > >Spark學習筆記11面向物件程式設計

Spark學習筆記11面向物件程式設計

面向物件程式設計

 

11.1 object類

11.1.1定義一個簡單的類

 

11.1.2 field的getter與setter

定義類包含,定義類的field及方法。其格式如下

class ClassName{ // 其中類名首字母要大寫

private var name = "Hys" // private修試符說明此變數只對本類有效

def sayHello(){ print("Hello," + name)

def getName = name // 獲取name 的值

}

建立類的物件,並呼叫其方法

val field_name = new ClassName // 建立類物件

field_name.sayHello() // 呼叫類方法

print(field_name.getName()) // 呼叫類成員

 

11.1.3 建構函式-constructor

 

11.1.4 內部類

 

11.2 物件

 

 

11.3 繼承

繼承的主要有點:可以減少程式碼量

11.3.1 關鍵字extends

*父類中用final修飾的field和method是無法被子類繼承的

示例程式碼:

class Person {

         private var name = "George"

def getName = name

}

class Student extends Person {

private var score = "A"

         def getScore = score

}

11.3.2 子類覆蓋父類field和method

    1.override關鍵字

        使用此關鍵字覆蓋可以幫助發現程式碼裡的錯誤

    2.父類方法被覆蓋之後還可以使用super呼叫父類方法

    示例程式碼:

        class Person{

private var name = "George"

def getName = name

}

class teacher extends Person{

private var age = 20

def getAge = age

override def getName = "Hello " + super.getName

}

    3. override field

    示例程式碼:

class Person{

val name:String = "Hys"

def age:Int = 20

}

class Teacher extends Person{

override val name:String = "George"

        override val age:Int = 30

}

    4.isInstanceOf 和 asInstanceOf

     isInstanceOf :判斷指定物件是否為指定類或其子類的物件,如果物件是null則一定返回false

     asInstanceOf:將指定物件轉換為指定型別

    示例程式碼:

        class Person

class Teacher extends Person

 

val p:Person = new Teacher

val t:Teacher = null

if(p.isInstanceOf[Teacher]) t = p.asInstanceOf[Teacher]

    5.getClass 和 classOf[類]

     p.getClass 可以獲取物件被例項化的型別

     classOf[類] 可以獲取精確的類

    示例程式碼:

    p.getClass == classOf[Person] 判斷p是否是被例項化為Person型別

    p.getClass == classOf[Teacher]

6. 模式匹配進行型別判斷

     *判斷物件是否和該類及其子類的物件

p match{

case per:Person => println("it's Person's object")

case _ => println("Unknown type")

}

    7.關鍵字protected

     *父類中使用protected 修試的field 和 method在子類中直接就可以訪問。

     *當使用protected[this]時只能在"子類 當前物件"中訪問父類的,其它物件不可以,包括同類物件。

    程式碼示例:

    class Person{

protected var name:String = "Hys"

}

class Teacher extends Person{

def sayHello() = {println("Hello " + name)}

}

val t = new Teacher

t.sayHello

8. 呼叫父類的建構函式constructor

*只能在子類的主constructor中呼叫父類的constructor;原因是輔建構函式只能呼叫本類的主建構函式或者輔建構函式

* 父類中接收的引數,子類中就不要用任何val 或者var 來修飾,否在認為是要覆蓋父類的field

示例程式碼:

class Person(val name:String, val age:Int)

class Teacher(name:String, age:Int, var score:Double) extends Person(name,age){

def this(name:String){

this(name,0,0)

}

def this(age:Int){

this("Hys",age,0)

}

}

8.呼叫父類的constructor

* 每個類的輔助建構函式(constructor)只能呼叫本類的輔助constructor或者主constructor,所以要呼叫父類建構函式必須使用子類的主建構函式。

*如果是父類中接收的引數,子類接收時就不要用var或者val 來修飾了,否則會認位是覆蓋父類的field 。

示例程式碼:

Class Person(val name:String, val age:Int){

    Println("Person's name is " + name)

    Println("Person's age is " + age)

}

Class Teacher(name:String, age:Int, var score:Double) extends Person(name, age){

    def this(name:String){

this(name:String)

}

def this(age:Int){

this("Hys ",age,0)

}

Println(name + " " + age + " " + score)

}

val t = new Teacher("George", 20, 100)

Person's name is George

Person's age is 20

George 20 100.0

9.匿名內部類

*匿名子類:定義的沒有名字的子類,同時直接建立其物件,然後將物件的引用賦予一個變數。然後匿名子類的物件也可以傳給其它函式。

示例程式碼:

class Person(protected val name:String){

def sayHello = "Hello, I'm " + name

}

val p = new Person("Hys") {

override def sayHello = "Nice to meet you " + name} //匿名子類

def greeting(p:person{def sayHello:String}){ //把匿名子類當成引數傳給函式

println(p.sayHello)

}

greeting(p) //呼叫匿名子類例項

10.抽象類

*抽象方法:定義時只有方法名和方法型別的方法。

*抽象類:包含抽象方法的類就是抽象類,即只要類中有一個抽象方法此類就為抽象類。

*抽象類必須用abstract關鍵詞修飾。

*抽象類不可以被例項化。

*在子類中覆蓋抽象類的方法時不需要用override關鍵字。

程式碼示例:

abstract class Person(){ //定義抽象類

def sayHello:String

}

class Teacher(name:String) extends Person{ //繼承抽象類

def sayHello:String = {println("Hello" + name ); name} // 覆蓋父類方法

}

val t = new Teacher("Hys")

t.sayHello

11.抽象field

*抽象field:定義field時只給出型別沒有給出初值,這樣的field就是抽象field。

*Scala會根據自己的規則為var或者val型別的field生成對應的getter和setter方法,但是父類中是沒有field的,就父類中的抽象field不佔記憶體。

*子類必須覆蓋父類的抽象field。

*子類覆蓋父類的抽象field不需要override關鍵字。

示例程式碼(子類不覆蓋父類抽象field報錯):

Abstract class Person{ //定義抽象類

Val name:String

}

class Teacher extends Person{} //子類不重寫程式碼,報錯

(子類正常繼承父類)

class Teacher extends Person{

val name:String = "Hys" // 覆蓋父類抽象方法

}

(子類把父類的抽象field繼承為抽象field操作)

class Teacher extends Person{ val name:String } // 把父類抽象方法繼承為抽象方法,如果不用abstract修飾子類會有報錯

abstract class Teacher extends Person{ val name:String} //正確的把父類抽象方法繼承為抽象方法

11.4 Trait

11.4.1基礎知識

1.將trait作為介面使用

*類使用關鍵字extends繼承

*與Java中的介面一樣

*抽象方法不需要overrid管家你

*Scala不支援對類進行多繼承,但可以多繼承trait,使用with關鍵字

程式碼示例:

trait HelloTrait{

def sayHello(name:String)

}

trait MakeFriendsTrait{

def makeFriends(p:Person)

}

class Person(val name:String) extends HelloTrait with MakeFriendsTrait with Cloneable with Serializable{

def sayHello(name:String) = println("Hello " + name)

def makeFriends(p:Person) = println("Hello, my name is " + name + " your name is " + p.name)

}

2.在trait中定義具體方法

*就像類中定義方法一樣

*不同之處在子類中呼叫是直接使用方法名就可以

trait computer{

def playVideo()={println("Play video")}

}

class Person extends computer{

playVideo()

def play()={playVideo()}

}

val p = new Person

p.playVideo

3.在trait中定義具體欄位

*與類繼承不同,trait定義的具體欄位直接新增到了繼承它的類中

trait Person{

val eyeNum:Int = 2

}

class Teacher(val name:String, val age:Int) extends Person{

println("Hello "+ name + ", you have " + eysNum + "eyes")

}

4.在trait中定義抽象欄位

*trait中可以定義抽象欄位,同時trait中的具體方法可以基於抽象欄位來寫,只不過繼承trait的類必須覆蓋抽象的field,提供具體的值

trait SayHello {

val name:String

def sayHello()={"Hello " + name}

}

 

class Person extends SayHello{

val name:String = "Hys" //覆蓋trait中抽象欄位

def makeFriends(p:Person){

sayHello()

println(name + ", nice to meet you")

}

}

11.4.2高階知識

1.為例項物件混入trait

*只有本物件可以呼叫

trait Loger{

def log(msg:String){print("loger trait")}

def logTrait(){println("loger trait")}

}

trait MyLoger extends Loger{

override def log(msg:String){println("log:" + msg)}

}

class Person(val name:String) extends Loger{

def sayHello{println("Hi,I'm " + name );log("sayHello is invoked!")}

}

val p2 = new Person("George") with MyLoger //動態混入trait

val p1 = new Person("Hys")

scala> p2.logTrait()

trait

scala> p1.log("")

loger trait

2.trait呼叫鏈

*繼承同一個trait的多個trait,在具有相同method的最後都執行super.method,就可以從右向左依次執行每個被繼承的多個trait中相同的方法,從而實現呼叫鏈。

程式碼示例:

trait Loger{

def vs(){}

def kk(){}

}

trait PersonReady extends Loger{

override def vs(){

println("I am ready")

super.vs() //執行此方法

}

}

trait PersonGo extends Loger{

override def vs(){

println("Please go!")

super.vs()

}

}

trait PersonEnd extends Loger{

override def vs(){

println("To be end!")

super.vs()

}

}

class PersonVs extends PersonEnd with PersonGo with PersonReady{

def aURD(name:String){

println("Are you ready")

vs() //執行呼叫鏈

}

}

3.在trait中覆蓋抽象方法

*當子trait呼叫super.method_name 時要要給子trait的方法加上abstract override修飾

示例程式碼1(無super.method_name呼叫):

trait Logger{

def log(msg:String)

}

trait Mylogger extends Logger{

override def log(msg:String){}

}

示例程式碼2(有super.method_name呼叫):

trait Logger{

def log(msg:String)

}

trait Mylogger extends Logger{

abstract override def log(msg:String){super.log("kk")} // 當呼叫super.method_name時要用abstract修飾

}

4.混合使用trait的具體方法和抽象方法

*可以讓trait中具體方法依賴於抽象方法,而抽象方法則放到繼承trait的類中去實現,就好像是一個模板

trait Valid{

def getName:String //在trait中定義抽象方法

def valid:Boolean={ //在trait中定義具體方法

getName == "Hys"

}

}

class Person(val name:String) extends Valid{

println(valid) //此語句需要執行的函式及次序是construceto->getName->vaild

def getName = {println("Get the name.")

name

}

}

5.trait的構造機制

*trait中不包含在任何方法中的程式碼就是trait的構造程式碼

*構造程式碼執行優先順序 父類建構函式->多個trait從左到右依次執行->父trait的構造程式碼->子類的建構函式

示例程式碼:

class Person{print("Person's constructor")}

trait Logger{println("\n Logger constructor")}

trait Logger{println("\n Logger constructor")}

trait TimeLogger extends Logger{println("TimeLogger")}

class Teacher extends Person with TimeLogger with MyLogger{println("Tescher class")}

例項化演示:

scala> val t = new Teacher

Person's constructor

Logger constructor

TimeLogger

Mylogger constructor

Tescher class

6.trait欄位的初始化

*trait不可以接收帶引數的建構函式,如果想使用trait初始化field,可以使用Scala的提前定義特性

示例程式碼:

trait SayHello{

val msg:String //需要初始化的欄位

println(msg.toString) // 對初始化欄位的呼叫

}

class Person

val p = new Person with SayHello //報錯

val p = new {val msg:String = "Hys" //提前定義

} Person with SayHello

或者

class Person extends { val msg:String = "Hys" //提前定義

} with SayHello

還有辦法就是使用lazy value

*如果不用lazy仍然會報異常

trait SayHello {

lazy val msg:String = null

println(msg:toString)

}

class Person extends SayHello //繼承的時候沒有用lazy,例項化時有異常發生

val p = new Person //有異常跳出

class Person extends SayHello{ override lazy val msg:String = "George"} //使用lazy覆蓋該field,例項化時正常

val p = new Person

7.讓trait繼承類

*trait也可以繼承自class,此時class就回成為所有繼承該trait的類的父類

示例程式碼:

class Hys { println("class Hys")}

trait George extends Hys {println("trait George")} //trait 繼承類

class Person extends George{println("class Person")} //之類繼承繼承了類的trait,此時trait繼承的類相當於繼承了該trait的父類。

scala> val p = new Person

class Hys

trait George

class Person

由建構函式執行內容和順序可知Hys類是Person的父類