Scala面向物件徹底精通及Spark原始碼閱讀
方法/步驟
一、Scala中的類實戰詳解類
跟Java一樣,Scala也是用關鍵字class來定義類。示例如下:
scala> class HiScala{
private var name = "Spark"
def sayName(){println(name)}
def getName = name
}
defined class HiScala
以上程式碼,定義了一個名稱為HiScala的類,預設情況下是public級別,所以public關鍵字可以不寫。
ü 定義了一個屬性name,為可變變數,訪問級別為private,在類的外面不能被訪問!
ü 定義一個函式:sayName
ü 定義一個函式:getName
在Scala中,變數與類中的方法是同等級的,可以直接相互賦值。
二、建立類例項
scala> val scal = new HiScala
scal: HiScala = [email protected]
//此時,scal就是HiScala類的一個例項。但是,在Scala中我們一邊不會用new來建立類的例項,而是用apply工廠方法模式來建立。
//呼叫scal的sayName方法,用於打印出name成員的值。
scala> scal.sayName()
Spark
//由於sayName沒有傳引數,所以可以把括號去掉,這樣更簡潔。
scala> scal.sayName
Spark
//呼叫getName方法,訪問name成員的值
scala> scal.getName
res2: String = Spark
//此時確實返回了name的值。
//該示例中name是私有的,所以不能直接訪問scal例項的name,如下訪問就出錯了。
scala> scal.name
scal.name
^
三、get與set
Scala的get和set跟Java的get和set有很大的差異。在Scala中,如果給變數前定義了private,那麼Scala直譯器會給這個變數自動生成private的get和set方 法;如果變數前沒有定義了private,那麼直譯器會給這個變數自動生成public的get和set方法,這樣就可以直接訪問該類的例項物件的成員變數,實際訪問的是它的set和get方法。
//我們重新改造上面的類,把屬性name前面的private訪問級別去掉。
scala> class HiScala{
var name ="Spark" //去掉了private關鍵字
defsayName(){println(name)}
def getName = name
}
defined class HiScala
scala> val scal = new HiScala
scal: HiScala = [email protected]
//訪問name屬性, 值為Spark
scala> scal.name
res4: String = Spark
//此時雖然是訪問屬性name,但其實不是直接訪問var指定的變數name,而是Scala直譯器自動給name生成public級別的get和set方法。
//修改name屬性
scala> scal.name="Scala"
scal.name: String = Scala
//再次訪問name屬性, 值已經變為Scala
scala> scal.name
res5: String = Scala
四、自定義的get和set
scala> class Person {
private var myName ="Flink"
def name = this.myName //自定義get方法
def name_=(newName : String){ //自定義set方法,注意下劃線和等號之間沒有空格!
myName = newName
println("Hi " + myName)
}
}
defined class Person
// luck為Person 類的例項
scala> val luck = new Person
luck: Person = [email protected]
//通過自定義的get方法,訪問到了myName屬性
scala> luck.name
res0: String = Flink
//呼叫自定義的set方法,修改了myName屬性
scala> luck.name = "Spark"
Hi Spark
luck.name: String = Spark
//再次訪問myName屬性,發現屬性值已經變成Spark
scala> luck.name
res2: String = Spark
//修改上面的示例,僅僅暴露屬性的get方法,沒有為其複寫set方法。但是提供一個名為update的方法用來修改該屬性的值。
scala> class Person {
private var myName ="Flink"
def name = this.myName //get方法
def update(newName :String){
myName = newName
println("Hi "+ myName)
}
}
defined class Person
// luck為Person 類的例項
scala> val luck = new Person
luck: Person = [email protected]
//通過自定義的get方法,訪問myName屬性值,初始值為Flink
scala> luck.name
res4: String = Flink
//想直接通過set方法來修改myName,會提示出錯,因為沒有複寫set方法。
scala> luck.name="Hadoop"
luck.name="Hadoop"
^
//通過額外提供的update方法來修改屬性
scala> luck.update("Hadoop")
Hi Hadoop
//再次檢視myName屬性值,發現已經變成了Hadoop
scala> luck.name
res6: String = Hadoop
四、private[this]
private[this]至關重要的,在Spark原始碼中隨處可見。代表屬性或方法為物件私有!在類私有的基礎上更強一層的控制。
//定義一個類:Person
scala> class Person {
private var myName ="Flink"
def name = this.myName
def update(newName :String){
myName = newName
println("Hi "+ myName)
}
def talk(p:Person) = {
println("hello:"+p.name)
}
}
defined class Person
//定義 p1為Person物件
scala> val p1=new Person
p1: Person = [email protected]
//定義 p2為Person物件
scala> val p2=new Person
p2: Person = [email protected]
//把p1的myName 屬性值改為p1
scala> p1.update("p1")
Hi p1
//把p2的myName 屬性值改為p2
scala> p2.update("p2")
Hi p2
//檢視p1的myName 屬性值,此時已經改為p1
scala> p1.name
res14: String = p1
//檢視p2的myName 屬性值,此時已經改為p2
scala> p2.name
res15: String = p2
//呼叫p1的talk方法,傳入p2物件,打印出p2的myName 屬性值
scala> p1.talk(p2)
hello:p2
//修改一下程式碼,看看下面程式碼:
scala>class Person {
private[this]var name = "Flink"
def update(newName : String){
name = newName
println("Hi " + name)
}
def talk(p:Person) = {
println("hello:"+p.name)
}
}
println("hello:"+p.name)
^
//此時,在定義類時就報錯!因為talk方法中p引數是Person類的物件,而name屬性被限制為private[this],所以只能在Person類內部使用,Person類的物件無權使用。也就是說在Person類中,update方法中可以使用name,但是talk方法訪問物件p的name是不允許的!
// private[this]改成private之後,下面的寫法就能正常定義,程式碼如下:
scala>class Person {
private varname = "Flink"
def update(newName : String){
name = newName
println("Hi " + name)
}
def talk(p:Person) = {
println("hello:"+p.name)
}
}
defined class Person
scala>
構造器的過載
scala> class Person {
private[this] var name ="Flink"
private[this] var age = 10
def update(newName :String){
name = newName
println("Hi "+ name)
}
//過載的構造器,首先呼叫預設的構造器
def this(name:String){
this()
this.name=name
}
//過載的構造器,呼叫上面已經存在的構造器
def this(name:String, age:Int){
this(name)
this.age=age
}
}
defined class Person