Scala的Class、Object、Trait
來自專欄 數據科學家的自我修養
開發環境
ideaIU或ideaIC。
idea的scala插件,File-Setting-Plugins,搜索scala在線安裝,或下載後離線安裝Install plugin from disk。
載入scala的包,Project Structure,Global Libraries,添加scala-sdk。
基礎
scala中,break和continue的實現,
package com.padluo.spark.scala.basicimport scala.util.control.Breaks._object BreakTest { def main(args: Array[String]): Unit = { // break breakable { for (i <- 1 to 10) { if (i == 2) { break() } println(i) } } // continue for (i <- 1 to 10) { breakable { if (i == 2) { break() } println(i) } } }}
0 until 10
和0 to 10
的區別,until是0到9,相當於<,to是0到10,相當於<=。
scala用Java裡面的類庫,
package com.padluo.spark.scala.basicimport java.text.SimpleDateFormatimport java.util.{Calendar, Date}object UseJava { def main(args: Array[String]): Unit = { val sdf:SimpleDateFormat = new SimpleDateFormat("yy-MM-dd") val c = Calendar.getInstance() println(c.getTime) println(sdf.format(c.getTime)) // Convert Code from Java,可以直接把Java代碼貼到scala文件中來 val sdf2: SimpleDateFormat = new SimpleDateFormat("yy-MM-dd") sdf2.format(new Date) }}
Class、Object、Trait
類class里無static類型,類里的屬性和方法,必須通過new出來的對象來調用,所以有main主函數也沒用。
而object的特點是:
- 可以擁有屬性和方法,且默認都是"static"類型,可以直接用object名直接調用屬性和方法,不需要通過new出來的對象(也不支持)。
- object里的main函數式應用程序的入口。
- object和class有很多和class相同的地方,可以extends父類或Trait,但object不可以extends object,即object無法作為父類。
類
構造函數,
- 一個主構造器(函數),其他是輔助構造器
- 輔助構造器的實現體里,必須引用(調用)主構造器
- 主構造器的參數,也會成為類的屬性(?正確嗎?)
- 輔助構造函數的名稱都是this
- 輔助構造函數中必須以一個其他輔助構造器或主構造器的調用開始
Bean屬性,定義getter和settet方法。
// TestVo.scalapackage com.padluo.spark.scala.basicimport scala.beans.BeanPropertyclass TestVo { // class 里的屬性默認是private類型,object里的屬性默認是static @BeanProperty var id = 10 @BeanProperty var name = null @BeanProperty var addr = null}// TestVoMain.scalapackage com.padluo.spark.scala.basicobject TestVoMain { def main(args: Array[String]): Unit = { var vo = new TestVo println(vo.getId) }}
伴生對象
如何實現同個類既有普通方法又有靜態方法?
伴生類和伴生對象可以相互訪問彼此的私有成員。
package com.padluo.spark.scala.basicclass BanSheng { def add2(a: Int, b: Int): Int = { a + b }}object BanSheng { def add(a: Int, b: Int): Int = { a + b } def main(args: Array[String]): Unit = { BanSheng.add(1, 2) // 靜態函數 val banSheng = new BanSheng banSheng.add2(3, 4) }}
javap BanSheng.class反編譯後,
public class com.padluo.spark.scala.basic.BanSheng { public static void main(java.lang.String[]); public static int add(int, int); public int add2(int, int); public com.padluo.spark.scala.basic.BanSheng();}
伴生對象的apply方法,
package com.padluo.spark.scala.basicclass BanSheng(id: Int) { def add2(a: Int, b: Int): Int = { a + b }}object BanSheng { def apply(id: Int): BanSheng = { println("----apply-----") new BanSheng(id) } def add(a: Int, b: Int): Int = { a + b } def main(args: Array[String]): Unit = { BanSheng.add(1, 2) // 靜態函數 val banSheng = new BanSheng(1) banSheng.add2(3, 4) val c = BanSheng(200) val cc = BanSheng.apply(200) }}
單例模式,
package com.padluo.spark.scala.basicclass SingleTon {}object SingleTon { private var s:SingleTon = null def getInstance():SingleTon = { if(s == null) { new SingleTon() } else { s } } def main(args: Array[String]): Unit = { val singleTon = SingleTon.getInstance() println(singleTon) }}
繼承
- 繼承關鍵詞extends,多個用with。
- 某類如果不想被繼承,可定義為final類型
- 用super調用父類的方法或屬性
- 重寫方法時必須用override,可以重寫欄位,不想被重寫則定義為final類型
- 只有主構造器可以調父類的主構造器
Father.scala
package com.padluo.spark.scala.basicclass Father(name: String, age: Int) { def doEat(food: String) { println("eatting .." + food) } def printInfo2() { println("name:" + name + ",age:" + age) }}
Son.scala
package com.padluo.spark.scala.basicclass Son(name: String, age: Int, addr: String) extends Father(name, age) { // 子類把name和age傳入到父類中 override def doEat(food: String) { println("my eatting .." + food) } def printInfo() { super.printInfo2() println("name:" + name + ",age:" + age + ",addr:" + addr) }}object Son { def main(args: Array[String]): Unit = { val s: Son = new Son("zhangsan", 30, "beijing") s.printInfo() }}
Scala類層級結構,
Scala里,每個類都繼承自通用的名為Any的超類。因為所有的類都是Any的子類,所以定義在Any中的方法就是「共同的」方法:它們可以被任何對象調用。
因為每個類都繼承自Any,所以Scala程序里的每個對象都能用==、!=或equals比較,用hashCode做散列,以及用toString轉為字元串。Any類里的等號和不等號方法被聲明為final,因此他們不能再子類里重寫。實際上,==
總是與equals相同,!=
總是與equeal相反。因此,獨立的類可以通過重寫equals方法改變==
或!=
的意義。
Any有兩個子類:AnyVal和AnyRef(相當於Java里的Object)。
AnyVal是Scala里每個內建值類的父類。有9個這樣的值類:Byte、Short、Char、Int、Long、Float、Double、Boolean和Unit。其中的前8個都對應到Java的基本類型。這些值類都被定義為既是抽象的又是final的,不能使用new創造這些類的實例。Unit被用作不返回任何結果的方法的結果類型。Unit只有一個實例值,寫成()。AnyRef類是Scala里所有引用類(reference class)的基類。它其實是Java平台上java.lang.Object類的別名。因此Java里寫的類和Scala里寫的都繼承自AnyRef。
Scala類與Java類的不同在於它們還繼承自一個名為ScalaObject的特別trait。是想要通過ScalaObject包含的Scala編譯器定義和實現的方法讓Scala程序的執行更高效。
scala.Null和scala.Nothing是用統一的方式處理Scala面向對象類型系統的某些「邊界情況」的特殊類型。Null類是null引用對象的類型,它是每個引用類(繼承自AnyRef的類)的子類。Null不兼容值類型。Nothing類型在Scala的類層級的最低端;它是任何其他類型的子類型。然而,根本沒有這個類型的任何值。Nothing的一個用處是它標明了不正常的終止。
Trait特質
為什麼不可以繼承多個父類?原因是多個父類里有相同函數或屬性時,無法控制用哪個。
Scala的Trait相當於Java里的Interface,但Trait不僅可以定義函數,還可以有函數體實現。實現關鍵詞是extends,實現多個Trait用with。當extends的多個Trait里有相同函數時,子類必須重寫該函數。
- 父trait里無函數體的函數,子類必須override
- 重寫父類里有函數體的函數,必須有關鍵詞override
- trait里的變數,都是val類型
- 在trait里定義的的變數,必須是val類型,如果變數沒初始化,子類必須override
案例1,
trait TestTrait { def fun()}
反編譯後為
public interface com.padluo.spark.scala.basic.TestTrait { public abstract void fun();}
當def fun()改為def fun(){} 時,反編譯結果如何?
trait TestTrait { def fun() {}}
反編譯後為(有問題???)
D:JavaideaIdeaProjectsspark-studyspark-core argetclassescompadluosparkscalaasic>javap TestTrait.classCompiled from "TestTrait.scala"public abstract class com.padluo.spark.scala.basic.TestTrait$class { public static void fun(com.padluo.spark.scala.basic.TestTrait); public static void $init$(com.padluo.spark.scala.basic.TestTrait);}D:JavaideaIdeaProjectsspark-studyspark-core argetclassescompadluosparkscalaasic>javap TestTrait$class.classCompiled from "TestTrait.scala"public abstract class com.padluo.spark.scala.basic.TestTrait$class { public static void fun(com.padluo.spark.scala.basic.TestTrait); public static void $init$(com.padluo.spark.scala.basic.TestTrait);}
案例2,
trait TestTrait { def fun() { println("---") } def fun200()}
反編譯後為(有問題)
D:JavaideaIdeaProjectsspark-studyspark-core argetclassescompadluosparkscalaasic>javap TestTrait.classCompiled from "TestTrait.scala"public abstract class com.padluo.spark.scala.basic.TestTrait$class { public static void fun(com.padluo.spark.scala.basic.TestTrait); public static void $init$(com.padluo.spark.scala.basic.TestTrait);}D:JavaideaIdeaProjectsspark-studyspark-core argetclassescompadluosparkscalaasic>javap TestTrait$class.classCompiled from "TestTrait.scala"public abstract class com.padluo.spark.scala.basic.TestTrait$class { public static void fun(com.padluo.spark.scala.basic.TestTrait); public static void $init$(com.padluo.spark.scala.basic.TestTrait);
本文首發於steem,感謝閱讀,轉載請註明。
https://steemit.com/@padluo
微信公眾號「padluo」,分享數據科學家的自我修養,既然遇見,不如一起成長。
http://weixin.qq.com/r/P3WGnj3E82CMrXn99yAt (二維碼自動識別)
讀者交流電報群
https://t.me/sspadluo
知識星球交流群
推薦閱讀:
※Spark源碼分析(3) RDD 的轉換
※spark在那裡指定master URL呢?
※Spark Streaming:大規模流式數據處理的新貴
※Spark里的DAG是怎麼回事?
※從頭學習大數據培訓課程 spark 基於內存的分散式計算框架(二)RDD 編程基礎使用