1:Scala之函數式編程學習筆記:
1:Scala函數式編程學習: 1.1:Scala定義一個簡單的類,包含field以及方法,創建類的對象,並且調用其方法: class User { private var name = "張三"; def hello(): Unit ={ println("hello : " + name) } //注:如果定義方法時不帶括號,則調用的時候也不可以加括號,否則報錯。 def getName = name; } //創建一個object來調用練習的實體類對象. object Hello { def main(args: Array[String]): Unit = { var user = new User; user.hello(); println(user.getName) } } 2:Scala中field字段的getter和setter詳解教程: 2.1:定義不帶private的var field,此時scala生成的面向jvm的類時,會定義為Private的name字段,並提供public的getter和setter的方法: class User { var name = "張三"; var age = 15; } //創建一個object來調用練習的實體類對象. object Hello { def main(args: Array[String]): Unit = { var user = new User; user.name="李四"; user.age=20; println(user.name + " " + user.age) } } 2.2:如果使用private修飾field,則生成的getter和setter也是private的: class User { private var name = "張三"; private var age = 15; } //創建一個object來調用練習的實體類對象. object Hello { def main(args: Array[String]): Unit = { var user = new User; //如果使用private修飾field,則生成的getter和setter也是private的,所以調用會報錯。 //println(user.name + " " + user.age) } } 2.3:如果定義val field,則只會生成getter方法: class User { val name = "張三"; val age = 15; } //創建一個object來調用練習的實體類對象. object Hello { def main(args: Array[String]): Unit = { var user = new User; //如果定義val field,則只會生成getter方法。所以調用setter方法會報錯的。 //user.name_="張三"; println(user.name + " " + user.age) } } 2.4:如果不希望生成setter和getter方法,則將field聲明為private[this]: class User { private[this] var name = "張三"; private[this] var age = 15; } //創建一個object來調用練習的實體類對象. object Hello { def main(args: Array[String]): Unit = { var user = new User; //則將field聲明為private[this],不生成setter和getter方法。所以調用setter和getter方法報錯 //user.name_="張三"; //println(user.name + " " + user.age) } } 2.5:調用getter和setter方法,分別叫做name和name_= class User { var name = "張三"; var age = 15; } //創建一個object來調用練習的實體類對象. object Hello { def main(args: Array[String]): Unit = { var user = new User; println(user.name + " " + user.age) //調用setter方法來修改值 user.name="李四"; println(user.name + " " + user.age) } } 2.6:如果只是希望擁有簡單的getter和setter方法,那么就按照scala提供的語法規則,根據需求為field選擇合適的修飾符就好:var,val,private,private[this]; 注意:如果希望能夠自己對gettter和setter進行控制,則可以自定義getter和setter方法,自定義setter方法的時候一定要注意scala的語法限制,簽名,=,參數間不能有空格 class User { var name : String = "張三"; var age : Int = 15; def getName = "my name is : " + name; def setName_=(newName : String): Unit ={ println("不可以修改你的姓名。") } } //創建一個object來調用練習的實體類對象. object Hello { def main(args: Array[String]): Unit = { var user = new User; user.name="李思思" println(user.getName + " " + user.age) } } 2.7:如果不希望field有setter方法,則可以定義為val,但是此時就再也不能更改field的值了。如果希望能夠僅僅暴漏出一個getter方法,並且還能通過某些方法更改field的值,那么需要綜合使用private以及自定義getter方法。此時,由於field是private的,所以setter和getter都是private的,對外界沒有暴漏,自己可以實現修改field值的方法;自己可以覆蓋getter方法。 class User { private var myName : String = "張三"; def updateName(newName : String): Unit ={ if(newName == "李四"){ myName = newName; }else{ println("此值不可以修改") } } def name = "you name is :" + myName; } //創建一個object來調用練習的實體類對象. object Hello { def main(args: Array[String]): Unit = { var user = new User; user.updateName("李四"); println(user.name) } } 2.8:如果將field使用private來修飾,那么代表這個field是類私有的,在類的方法中,可以直接訪問類的其他對象的private field;這種情況下,如果不希望field被其他對象訪問到,那么可以使用private[this],意味着對象私有的field,只有本對象內可以訪問到。 class User { private[this] var myAge : Int = 0; def age_=(newAge : Int): Unit ={ if(newAge > 0){ myAge = newAge; }else println("不合法的年齡") } def age = myAge; //使用private[this],意味着對象私有的field,只有本對象內可以訪問到。 //def orderAge(user : User) ={ //myAge > user.myAge; //} } //創建一個object來調用練習的實體類對象. object Hello { def main(args: Array[String]): Unit = { var user = new User; user.age_=(20); println(user.age) user.age = 24; println(user.age) var user2 = new User; user2.age_=(25); if(user2.orderAge(user)){ println("user2 大於 user") }else{ println("user2 小於 user") } } } 2.9:Scala的getter和setter方法的命名與java是不同的,是field和field_=的方式,如果要讓scala自動生成java風格的getter和setter方法,只要給field添加@BeanProperty注解即可;此時會生成4個方法,name:String,name_=(newName:String):Unit,getName():String,setName_(newValue:String):Unit; class User { @BeanProperty var name : String = _; } //創建一個object來調用練習的實體類對象. object Hello { def main(args: Array[String]): Unit = { var user = new User; user.setName("張三"); println(user.getName); user.name_=("李思思"); println(user.name) } } 3:Scala中constructor詳解: 3.1:Scala中,可以給類定義多個輔助constructor,類似於java中的構造函數重載;輔助constructor之間可以互相調用,而且必須第一行調用主constructor class User { @BeanProperty var name : String = _; @BeanProperty var age : Int =_; def this(name: String){ this(); this.name = name; } def this(name : String, age :Int){ this(name); this.age = age; } } //創建一個object來調用練習的實體類對象. object Hello { def main(args: Array[String]): Unit = { var user = new User; var user2 = new User("張三"); var user3 = new User("李四",26); } } 3.2:Scala中,主構造constructor是與類名放到一起的,與java不同。而且類中,沒有定義在任何方法或者是代碼塊之中的代碼,就是主constructor的代碼,這是感覺沒有java那么清晰; 注意:如果主constructor傳入的參數什么修飾都沒有,比如name:String。那么類內部的方法使用到了,則會聲明為private[this] name,否則沒有該field,就只能被constructor代碼使用而已。 class User(name : String, age : Int) { println("you name is :" + name + ", you age is : "+ age) var id : Int = _; } //創建一個object來調用練習的實體類對象. object Hello { def main(args: Array[String]): Unit = { var user = new User("張三",16); user.id_=(20); println("you id is :" +user.id) } } 3.3:主構造方法constructor方法中還可以通過使用默認參數,來給參數默認的值: class User(val name : String="李思思", age : Int = 18) { println("you name is :" + name + ", you age is : "+ age) var id : Int = _; } //創建一個object來調用練習的實體類對象. object Hello { def main(args: Array[String]): Unit = { var user = new User(); user.id_=(20); println("you id is :" +user.id) } } 4:Scala中內部類的介紹: 4.1:在Scala中,同樣可以在類中定義內部類,但是與java不同的是,每個外部類的對象的內部類,都是不同的類: class User { class Student(val name : String){}; val students = new ArrayBuffer[Student]; def getStudent(name : String) = { new Student(name); } } //創建一個object來調用練習的實體類對象. object Hello { def main(args: Array[String]): Unit = { val user1 = new User(); val stu = user1.getStudent("張三"); println(stu) user1.students += stu; var user2 = new User; var stu2 = user2.getStudent("李四"); println(stu2) //下面這一行報錯,好好體會一下 //user1.students += stu2; } }
2:Scala之Object對象學習筆記:
1:Object對象: 1.1:object對象,相當於class的單個實例,通常在里面放一些靜態的field或者method;第一次調用object的方法時候,就會執行object的constructor構造方法,也就是Object內部不在method中的代碼;但是Object不能定義接受參數的constructor;object通常用於作為單例模式的實現,或者放class的靜態成員,比如工具方法; 注意:object的constructor只會在其第一次被調用的時候執行一次,以后再次調用就不會執行constructor了。 object Hello { private val name = "張三"; println("this is object Hello"); def show(): Unit ={ println("一步一個腳印"); } def getName = name; def main(args: Array[String]): Unit = { show() println(getName); println(Hello.getName) } }
3:Scala之伴生對象學習筆記:
1:伴生對象,如果有一個class,還有一個與class同名的Object,那么就稱這個object是class的伴生對象,class是object的伴生類;伴生類與伴生對象必須存放在一個.scala文件之中;伴生類與伴生對象,最大的特點就是在於,互相可以訪問private field;
4:Scala之繼承學習筆記:
1:讓object繼承抽象類: 1.1:object的功能其實和class類似,除了不能定義接受參數的constructor之外,object也可以繼承抽象類,並且覆蓋抽象類中的方法: abstract class User(val name : String) { def hello(name : String): Unit ={ //println("you name is : "+ name) } } //創建一個Object繼承User類 object UserImpl extends User("張三"){ override def hello (name: String): Unit = { println("you name is :" + name) } } //創建一個Object來進行測試 object Test { def main(args: Array[String]): Unit = { //object的功能其實和class類似,除了不能定義接受參數的constructor之外 var ui = UserImpl; //方式一 ui.hello("李四"); //方式二 UserImpl.hello("王五"); } } 2:Apply方法,object中非常重要的一個特殊方法,就是apply方法。通常在伴生對象中實現apply方法,並在其中實現構造伴生類的對象的功能。而創建伴生類的對象時,通常不會使用new Class的方式,而是使用Class()的方式,隱式的調用伴生對象得到apply方法,這樣會讓對象創建更加簡潔: 2.1:比如,Array類的伴生對象的apply方法就實現了接受可變數量的參數,並且創建一個Array對象的功能: var arr = Array(1,2,3,4,5,6,7,8,9); 2.2:比如,定義自己的伴生類和伴生對象: class Person(val name : String) { } //創建伴生對象 object Person{ def apply(name : String) = new Person(name) } //創建Object進行測試 object Test { def main(args: Array[String]): Unit = { val p1 = new Person("張三"); println(p1.name); val p2 = Person("李思思"); println(p2.name); } } 3:main方法,就如同java中,如果要運行一個程序,必須編寫一個包含main方法類一樣,在scala中,如果想要運行一個應用程序,那么必須有一個main方法,作為入口; 3.1:注意:scala中的main方法定義為def main(args: Array[String]): Unit = {}。而且必須定義在object中; App Trait的工作原理,App Trait繼承自DelayedInit Trait,scalac命令進行編譯時候,會把繼承App Trait的object的construtcor代碼都放到DelayedInit Trait的delayedInit方法中執行; object Test { def main(args: Array[String]): Unit = { } } 3.2:除了自己實現main方法以外,還可以繼承App Trait,然后將需要在main方法中運行的代碼,直接作為Object的construstor代碼。而且用args可以接受傳入的參數: object Test extends App{ if(args.length > 0){ println("hello : " + args(0)) }else println("hello 你妹啊 hello.") } 4:用object來實現枚舉功能: 4.1:scala沒有直接提供類似於java中的Enum這樣的枚舉特性,如果要實現枚舉,則需要用Object繼承Enumeration類,並且調用value方法來初始化枚舉值: object Season extends Enumeration{ val SPRING,SUMMER,AUTUMN,WINTER = Value; } 4.2:還可以通過value傳入枚舉值的id和name,通過id和toString可以獲取,還可以通過id和name來查找枚舉值: object Season extends Enumeration{ // val SPRING,SUMMER,AUTUMN,WINTER = Value; val SPRING = Value(0,"spring"); val SUMMER = Value(1,"summer"); val AUTUMN = Value(2,"autumn"); val WINTER = Value(3,"winter"); def main (args: Array[String]): Unit = { println(Season(0)); println(Season.withName("spring")); } } 4.3:使用枚舉object.values可以遍歷枚舉值: object Season extends Enumeration{ //val SPRING,SUMMER,AUTUMN,WINTER = Value; val SPRING = Value(0,"spring"); val SUMMER = Value(1,"summer"); val AUTUMN = Value(2,"autumn"); val WINTER = Value(3,"winter"); def main (args: Array[String]): Unit = { for(i <- Season.values){ println(i) } } }
5:Scala中,讓子類繼承父類,與Java一樣,也是使用extends關鍵字;
5.1:繼承就代表,子類可以從父類繼承父類的field和method,然后子類可以在自己內部放入父類沒有的field或者method;子類擁有特有的field和method,使用繼承可以有效的復用代碼。
class Person {
private var name : String = "張三";
def getName = name;
def setName_=(name : String): Unit ={
println("private修改的字段,生成的setter和getter也是私有的。")
}
}
//創建一個Student類來繼承Person類:
class Student extends Person{
private var score : Int = 60;
def getScore = score;
def setScore_=(score : Int): Unit ={
println("private修改的字段,生成的setter和getter也是私有的。")
}
}
//創建一個Object來調用創建的Student或者Person類:
object HelloWorld {
def main(args: Array[String]): Unit = {
var student = new Student();
println("my name is : " + student.getName + ", and my score is : " + student.getScore);
}
}
5.2:子類可以覆蓋父類的field和method,但是如果父類用final修飾,field和method用final修飾,則該類是無法被繼承的,field和method是無法被覆蓋的。
//父類用final修飾
final class Person {
private var name : String = "張三";
def getName = name;
def setName_=(name : String): Unit ={
println("private修改的字段,生成的setter和getter也是私有的。")
}
}
//創建一個Student類來繼承Person類:
class Student extends Person{
private var score : Int = 60;
def getScore = score;
def setScore_=(score : Int): Unit ={
println("private修改的字段,生成的setter和getter也是私有的。")
}
}
//創建一個Object來調用創建的Student或者Person類:
object HelloWorld {
def main(args: Array[String]): Unit = {
var student = new Student();
//父類用final修飾,則該類是無法被繼承的,所以下面會報錯
//println("my name is : " + student.getName + ", and my score is : " + student.getScore);
}
}
6:Scala中的override和super:
6.1:Scala中,如果子類要覆蓋一個父類中的非抽象方法,則必須使用override關鍵字;override關鍵字可以幫助我們盡早的發現代碼里面的錯誤,比如,override修改的父類方法的方法名我們拼寫錯誤了,比如要覆蓋的父類方法的參數我們寫錯了等等。此外,在子類覆蓋父類方法以后,如果我們在子類中就要調用父類的被覆蓋的方法呢?那就可以使用super關鍵字,現實的指定要調用父類的方法。
class Person {
private var name : String = "張三";
def getName = name;
def setName_=(name : String): Unit ={
println("private修改的字段,生成的setter和getter也是私有的。")
}
}
//創建一個Student類來繼承Person類:
class Student extends Person{
private var score : Int = 60;
def getScore = score;
def setScore_=(score : Int): Unit ={
println("private修改的字段,生成的setter和getter也是私有的。")
}
//方法的覆蓋,使用關鍵詞override和super
override def getName: String = "Student類繼承Person,且覆蓋getName方法:" + super.getName;
}
//創建一個Object來調用創建的Student或者Person類:
object HelloWorld {
def main(args: Array[String]): Unit = {
var student = new Student();
println("my name is : " + student.getName + ", and my score is : " + student.getScore);
}
}
6.2:Scala中,子類可以覆蓋父類的val field,而且子類的val field還可以覆蓋父類的val field的getter方法;只要在子類中使用override關鍵字即可;
class Person {
val name : String = "張三";
def age : Int = 0;
}
//創建一個Student類來繼承Person類:
class Student extends Person{
override val name : String = "李四";
override val age : Int = 20;
}
//創建一個Object來調用創建的Student或者Person類:
object HelloWorld {
def main(args: Array[String]): Unit = {
var student = new Student();
println("my name is : " + student.name + ",my age is :" + student.age);
}
}
7:isInstanceOf和asInstanceOf,如果我們創建了子類的對象,但是又將其賦予了父類類型的變量。則在后續的程序中,我們又需要將父類類型的變量轉換為子類類型的變量。首先,需要使用isInstanceOf判斷對象是否是指定類的對象,如果是的話,則可以使用asInstanceOf將對象轉換為指定類型。
注意:如果對象是null,則isInstanceOf一定返回false,asInstanceOf一定返回null;
如果沒有用isInstanceOf先判斷對象是否為指定類的實例,就直接用asInstanceOf轉換,則可能會拋出異常;
class Person {
var name : String = "張三";
var age : Int = 20;
}
//創建一個Student類來繼承Person類:
class Student extends Person{
var sex : String ="男";
}
//創建一個Object來調用創建的Student或者Person類:
object HelloWorld {
def main(args: Array[String]): Unit = {
//父類的變量引用了子類的對象.
val p : Person = new Student;
var s : Student = null;
//注意是[]不是(),否則報錯。
if(p.isInstanceOf[Student]){
s = p.asInstanceOf[Student];
}
println(" my name is :"+ s.name + " ,my age is :" + s.age)
}
}
8:getClass和classOf,isInstanceOf只能判斷出對象是否是指定類以及其子類的對象,而不能精確判斷出,對象就是指定類的對象。如果要求精確的判斷對象就是指定類的對象,那么只能使用使用getClass和classOf了。
用法如下所示:
對象.getClass可以精確獲取對象的類,classOf[類]可以精確獲取類沒然后使用==操作符即可判斷:
class Student extends Person{
var sex : String ="男";
}
//創建一個Student類來繼承Person類:
class Person {
var name : String = "張三";
var age : Int = 20;
}
//創建一個Object來調用創建的Student或者Person類:
object HelloWorld {
def main(args: Array[String]): Unit = {
//父類的變量引用了子類的對象.
val p : Person = new Student;
var s : Student = null;
//注意是[]不是(),否則報錯。
if(p.isInstanceOf[Student]){
s = p.asInstanceOf[Student];
}
println("======================================================================")
//注意,isInstanceOf不可以精確判斷是子類還是父類的。
if(p.isInstanceOf[Person] && p.isInstanceOf[Student]){
println("0:p指向了Person,也指向了Student");
}
println("======================================================================")
println(" my name is :"+ s.name + " ,my age is :" + s.age)
if(p.getClass == classOf[Person]){
//p指向的是Student;
println("1:getClass的用法:" + p.getClass + ",classOf的用法:" + classOf[Person]);
}
println("======================================================================")
if(p.getClass == classOf[Student]){
println("2:getClass的用法:" + p.getClass + ",classOf的用法:" + classOf[Student]);
}
println("======================================================================")
val p2 : Person = new Person;
if(p2.getClass == classOf[Person]){
//p2指向的是Person;
println("3:getClass的用法:" + p2.getClass + ",classOf的用法:" + classOf[Person]);
}
}
}
9:使用模式匹配進行類型判斷:
9.1:在實際開發中,比如Spark的源碼中,大量的地方都是使用了模式匹配的方式進行類型的判斷,這種方式更加的簡潔明了,而且代碼的維護性和可擴展性也很高。
使用模式匹配,功能性上來說,與instanceOf一樣,也是判斷主要是該類以及該類的子類的對象即可,不是精確判斷的:
class Student extends Person{
var sex : String ="男";
}
//創建一個Student類來繼承Person類:
class Person {
var name : String = "張三";
var age : Int = 20;
}
//創建一個Object來調用創建的Student或者Person類:
object HelloWorld {
def main(args: Array[String]): Unit = {
//父類的變量引用了子類的對象.
val p : Person = new Student;
//模式匹配
p match {
case person : Person => println("It is Person class");
case student : Student => println("It is Student class");
case _ => println("不知道是什么類型的.");
}
}
}
10:Protected關鍵字,跟java一樣,scala中同樣可以使用protected關鍵字來修飾field和method,這樣在子類中就不需要super關鍵字,直接就可以訪問field和method;
10.1:注意:還可以使用protected[this],則只能在當前子類對象中訪問父類的field和method,無法通過其他子類對象訪問父類的field和method;
class Person {
protected var name : String = "張三";
protected[this] var age : Int = 20;
}
//創建一個Student類來繼承Person類:
class Student extends Person{
var sex : String ="男";
def showPerson(): Unit ={
println("my name is : " + name);
}
def makeFriends(s : Student): Unit ={
//還可以使用protected(this)則只能在當前子類對象中訪問父類的field和method,
//無法通過其他子類對象訪問父類的field和method;
//下面的s.age會報錯的。protected[this] var age : Int = 20;
//println("my age is : " + age + ",you age is : " + s.age);
}
}
11:調用父類的constructor,在scala中,每個類可以有一個主constructor和任意多個輔助constructor,而每個輔助constructor的第一行都必須是調用其他輔助constructor或者是主constructor;因此子類的輔助constructor是一定不可能直接調用父類的constructor的;
注意:只能在子類的主constructor中調用父類的constructor,以下這種語法,就是通過子類的主構造函數來調用父類的構造函數;如果是父類中接受的參數,比如name和age,子類中接受時,就不要用任何val或者var來修飾了,否則會認為是子類要覆蓋父類的field;
class Person(val name : String,val age : Int) {
}
//創建一個Student類來繼承Person類:
class Student(name : String,age : Int,var score : Int) extends Person(name,age){
def this(name : String){
this(name,0,0);
}
def this(age : Int){
this("張三",age,0);
}
}
//創建一個Student類來繼承Person類:
object HelloWorld {
def main(args: Array[String]): Unit = {
var student = new Student("李思思",22,100);
println(student.name + " " + student.age + " " + student.score)
var student2 = new Student("王五");
println(student2.name + " " + student2.age + " " + student2.score)
var student3 = new Student(20);
println(student3.name + " " + student3.age + " " + student3.score)
}
}
12:匿名子類,在Scala中,匿名子類是非常常見,而且非常強大的。Spark的源碼中也大量使用了這種匿名子類。
匿名子類,也就是說,可以定義一個類的沒有名稱的子類,並且直接創建其對象,然后將對象的引用賦予一個變量。之后甚至可以將該匿名子類的對象傳遞給其他函數。
class Person(protected val name : String) {
def hello()= "hello, I am :" + name;
}
//創建一個Student類來繼承Person類:
object HelloWorld {
def main(args: Array[String]): Unit = {
//匿名內部類
var p = new Person("張三"){
override def hello(): String = "匿名內部類,hello :" + name;
}
//調用
println(p.hello());
}
}
13:抽象類,如果在父類中,有某些方法無法立即實現,而需要依賴不同的子類來覆蓋,重寫實現自己不同的方法實現。此時可以將父類中的這些方法不給出具體的實現,只有方法簽名,這種方法就是抽象方法;
13.1:注意:一個類中如果有一個抽象方法,那么類就必須用abstract來聲明為抽象類,此時抽象類是不可以實例化的。
在子類中覆蓋抽象類的抽象方法時,不需要使用override關鍵字;
abstract class Person(val name : String) {
def hello() : Unit;
}
//創建一個Student類來繼承Person類:
class Student(name : String) extends Person(name){
override def hello(): Unit = println("hello : " + name);
}
//創建一個Student類來繼承Person類:
object HelloWorld {
def main(args: Array[String]): Unit = {
var student = new Student("張三")
student.hello()
}
}
13.2:抽象field,如果在父類中,定義了field,但是沒有給出原始值,則此field為抽象field;
抽象field意味着,scala會根據自己的規則,為var或者val類型的field生成對應的getter和setter方法,但是父類中是沒有該field的。
子類必須覆蓋field,以定義自己的具體field,並且覆蓋抽象field,不需要使用override關鍵字;
abstract class Person {
val name : String;
}
//創建一個Student類來繼承Person類:
class Student extends Person{
val name : String= "張三";
}
//創建一個Student類來繼承Person類:
object HelloWorld {
def main(args: Array[String]): Unit = {
var student = new Student
println(student.name)
}
}
5:Scala之面向對象編程之Trait學習筆記:
1:trait基礎知識: 1.1:將trait作為接口使用: a、Scala中的trait是一種特殊的概念,首先我們可以將trait作為接口來使用,此時的trait就與Java中的接口非常類似; b、在trait中可以定義抽象方法,就與抽象類中的抽象方法一樣,只要不給出方法的具體體現即可; c、類可以使用extends關鍵字來繼承trait,注意,這里不是implement,而是extends,在scala中沒有implmemts的概念, 無論繼承還是trait,統一都是extends; d、類繼承trait后,必須實現其中的抽象方法,實現時候不需要使用override關鍵字; e、scala不支持對類進行多繼承,但是支持多重繼承trait,使用with關鍵字即可; trait Person { def hello(name : String); } //定義一個MakeFriends的trait trait MakeFriends { def makeFriends(friend: Friend); } //定義一個類來繼承上面兩個trait class Friend(val name : String) extends Person with MakeFriends with Cloneable with Serializable{ def hello(name: String) = println("my name is : " +name) def makeFriends(friend: Friend) = println("hello,my name is : " + name + ",your name is :" + friend.name); } //定義一個object來測試實現的類 object HelloWorld { def main(args: Array[String]): Unit = { var friend = new Friend("張三"); var friend2 = new Friend("李四"); friend.hello("李四"); friend.makeFriends(friend2); } } 1.2:在trait中定義具體方法: Scala中的trait可以不是只定義抽象方法,還可以定義具體方法,此時trait更像是包含了通用工具方法的東西,有一個專有的名詞來形容這種情況,就是說trait的功能混入了類。舉例來說,trait中可以包含一些很多類都通用的功能方法,比如打印日志等等,Spark中就使用了trait來定義了通用的日志打印方法: trait Logger { def log(message : String) = println(message); } //定義一個類來實現trait接口
class User(val name : String) extends Logger{
def makeFriends(user: User): Unit ={
println("hello, i am " + name + " i am nice to meet you :" + user.name);
log("makeFriends logger User[name="+user.name+"]");
}
}
//定義一個object來測試實現的類
object HelloWorld {
def main(args: Array[String]): Unit = {
val user = new User("張三");
val user2 = new User("李思思");
user.makeFriends(user2);
}
}
1.3:在trait中定義具體字段: Scala中的triat可以定義具體field,此時繼承triat的類就自動獲得了triat中定義的field,但是這種獲取field的方式與繼承class不同:如果是繼承class獲取的field,實際是定義在父類中的,而繼承triat獲取的field,就直接被添加到了類中。
trait Person {
def hello();
//定義一個field
val eyeNum : Int =2;
}
//定義一個類來實現trait接口
class Friend(val name : String) extends Person{
def hello() = println("my name is : " +name + ",and i have : " +eyeNum + "eyes");
}
//定義一個object來測試實現的類
object HelloWorld {
def main(args: Array[String]): Unit = {
var friend = new Friend("張三");
friend.hello();
}
} 1.4:在trait中定義抽象字段: Scala中的Triat可以定義抽象field,而Triat中的具體方法則可以基於抽象field來編寫,但是繼承Triat的類,則必須覆蓋抽象field,提供具體的值:
trait Person {
//定義一個抽象的field
val msg : String;
//Triat中的具體方法則可以基於抽象field來編寫
def hello(name : String) = println(msg + " ," + name);
}
//定義一個類來實現trait接口
class Friend(val name : String) extends Person{
//但是繼承Triat的類,則必須覆蓋抽象field,提供具體的值;
val msg : String = "hello";
def makeFriends(p : Person)={
hello(name)
println("my name is : " + name,",and i want to make friends with you.")
}
}
//定義一個object來測試實現的類
object HelloWorld {
def main(args: Array[String]): Unit = {
var friend = new Friend("張三");
var friend2 = new Friend("張三");
friend.makeFriends(friend2)
}
} 2:trait高級知識: 2.1:位實例對象混入trait: 有時候,我們可以在創建類的對象的時候,指定該對象混入某個trait,這樣,就只有這個對象混入該trait的方法,而類的其他對象則沒有:
import scala.util.logging.Logged
trait MyLogged extends Logged{
override def log(msg: String): Unit = {
println("log : " + msg);
}
}
//定義一個類來實現trait接口
import scala.util.logging.Logged
class Person(name : String) extends Logged{
def hello(): Unit ={
println("hi , i am is :" + name);
}
log("hello is invoked");
}
//定義一個object來測試實現的類
object Object {
def main(args: Array[String]): Unit = {
var person1 = new Person("張三");
person1.hello();
var person2 = new Person("李思思") with MyLogged;
person2.hello()
}
} 2.2:trait調用鏈: a、Scala中支持讓類繼承多個Trait后,依次調用多個trait中的同一個方法,只要讓多個trait的同一個方法中,在最后都執行super方法即可;
b、類中調用多個trait中都有的這個方法時,首先會從最右邊的trait的方法開始執行,然后依次往左執行,形成一個調用鏈條;
c、這種特性非常強大,其實就相當於設計模式中的責任鏈模式的一種具體實現依賴;
trait Handler {
def handler(data : String){}
}
//定義一個trait來實現trait接口
trait DataValidHandler extends Handler{
override def handler(data: String): Unit = {
println("check data : " + data);
super.handler(data)
}
}
//定義一個trait來實現trait接口
trait SignatureValidHandler extends Handler{
override def handler(data: String): Unit = {
println("signature : " + data)
super.handler(data)
}
}
//定義一個類來實現trait接口
class Person(val name : String) extends SignatureValidHandler with DataValidHandler{
def hello(): Unit ={
println("hello :" + name);
handler(name);
}
}
//定義一個object來測試實現的類
object Object {
def main(args: Array[String]): Unit = {
val p1 = new Person("張三");
p1.hello();
}
} 2.3:在trait中覆蓋抽象方法【注意語法】: 在Trait中,是可以覆蓋父trait的抽象方法的。但是覆蓋時,如果使用了super.方法的代碼,則無法通過編譯。因為super.方法就會去掉用父trait的抽象方法,此時子trait的該方法還是會被認為是抽象的。此時如果要通過編譯,就得給子trait的方法加上abstract override修飾:
trait MyLogged extends Logged{
abstract override def log(msg: String): Unit = {
super.log(msg)
}
} 2.4:混合使用trait的具體方法和抽象方法: trait Valid {
def getName : String;
def valid : Boolean = {
getName == "張三";
}
}
//定義一個類來實現trait接口
class Person(val name : String) extends Valid{
println(valid)
def getName = name;
}
//定義一個object來測試實現的類
object Object {
def main(args: Array[String]): Unit = {
var p1 = new Person("張三");
}
} 2.5:trait的構造機制: 在Scala中,trait也是有構造方法的,也就是trait中的,不包含在任何方法中的代碼。而繼承了trait的類的構造機制如下所示:
a、父類的構造函數執行。
b、trait的構造代碼執行,多個trait從坐到右依次執行。
c、構造trait的時候會先構造父類trait,如果多個trait繼承同一個父trait,則父trait只會構造一次。
d、所有trait構造完畢以后,子類的構造函數執行。
trait Logger {
println("logger constructor")
}
//定義一個trait來實現trait接口
trait Mylogger extends Logger{
println("Mylogger constructor")
}
//定義一個trait來實現trait接口
trait TimeLogger extends Logger{
println("TimeLogger constructor");
}
//定義一個class
class Person{
println("person construcotr")
}
//定義一個class繼承類和trait
class Student extends Person with Mylogger with TimeLogger{
println("Student constructor")
}
//定義一個object來測試實現的類
object Object {
def main(args: Array[String]): Unit = {
val s1 = new Student();
}
} 2.6:trait字段的初始化: 在Scala中,trait也是有構造方法的,也就是trait中的,不包含在任何方法中的代碼。而繼承了trait的類的構造機制如下所示:
a、父類的構造函數執行。
b、trait的構造代碼執行,多個trait從坐到右依次執行。
c、構造trait的時候會先構造父類trait,如果多個trait繼承同一個父trait,則父trait只會構造一次。
d、所有trait構造完畢以后,子類的構造函數執行。
trait Logger {
println("logger constructor")
}
//定義一個trait來實現trait接口
trait Mylogger extends Logger{
println("Mylogger constructor")
}
//定義一個trait來實現trait接口
trait TimeLogger extends Logger{
println("TimeLogger constructor");
}
//定義一個class
class Person{
println("person construcotr")
}
//定義一個class繼承類和trait
class Student extends Person with Mylogger with TimeLogger{
println("Student constructor")
}
//定義一個object來測試實現的類
object Object {
def main(args: Array[String]): Unit = {
val s1 = new Student();
}
} 2.7:讓trait繼承類: 在Scala中,trait是沒有接受參數的構造函數的,這是trait與class的唯一區別,但是如果需求就是要trait能夠對field進行初始化,那么只能使用Scala中非常特殊的一種高級特性--提前定義:
//1:第一種方式實現:
trait Hello {
val msg : String;
println(msg.toString);
}
//定義一個class繼承類和trait
class Person extends {
val msg : String = "init";
}with Hello{}
//定義一個object來測試實現的類
object Object {
def main(args: Array[String]): Unit = {
var p1 = new Person();
}
}
//2:第二種方式實現:
trait Hello {
lazy val msg : String = null;
println(msg.toString);
}
//定義一個class繼承類和trait
class Person extends Hello{
override lazy val msg: String = "init"
}
//定義一個object來測試實現的類
object Object {
def main(args: Array[String]): Unit = {
var p1 = new Person();
}
}
2.7:讓trait繼承類:
在Scala中,trait也可以繼承自class,此時這個class就會成為所有繼承該trait的類的父類;
class MyUtil {
def printMessage(msg : String) = println("msg : " + msg);
}
//定義一個trait實現class
trait Logger extends MyUtil{
def log(msg : String) = printMessage("log :" + msg);
}
//定義一個class實現trait
class Person(val name : String) extends Logger{
def hello(): Unit ={
log("hi , i am : " + name);
printMessage("hi , i am : " + name);
}
}
//定義一個object來測試實現的類
object Object {
def main(args: Array[String]): Unit = {
val p = new Person("張三");
p.hello()
}
}
待續......