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的父類