1. 程式人生 > 其它 >Scala--面向物件

Scala--面向物件

技術標籤:Scala大資料scala

目錄

1. 什麼是面向物件

  • 面向物件(Object Oriented)是軟體開發方法,一種程式設計正規化,面向物件是一種對現實世界理解和抽象的方法,是計算機程式設計技術發展到一定階段後的產物。
  • 我們經常說Java是一種面向物件的語言,其中三大特性為:封裝、繼承、多型。

2. Scala class的使用

2.1 建立一個簡單的類

class SimpleClass {

  val name: String = "spark"
  var age: Int = _

  def eat(): Unit = {
    println(s"$name eat")
  }
}

2.2 在Linux上面進行編譯

[[email protected] scala]# pwd
/root/script/scala
[[email protected]
scala]# vim SimpleClass.scala class SimpleClass { val name: String = "spark" var age: Int = _ def eat(): Unit = { println(s"$name eat") } } [[email protected] scala]# scalac SimpleClass.scala [[email protected] scala]# ls SimpleClass.class SimpleClass.scala

2.3 反編譯Class

[[email protected] scala]# javap -p SimpleClass.class 
Compiled from "SimpleClass.scala"
public class SimpleClass {
  private final java.lang.String name;
  public java.lang.String name();
  private int age;
  public int age();
  public void age_$eq(int);
  public void eat();
  public SimpleClass();
}
  • val name 對應private final java.lang.String name; public java.lang.String name();只能從這個類中得到name這個屬性的資料,無法修改name 這個屬性的資料。
  • var age:對應private int age; public int age(); public void age_$eq(int); 可以從此類中得到age資料,並且可以修改age資料。

2.4 SimpleClassApp Code

package com.xk.bigdata.scala.oo

object SimpleClassApp {

  def main(args: Array[String]): Unit = {
    val simpleClass = new SimpleClass
    simpleClass.age_$eq(16)
    println(s"${simpleClass.name}========>${simpleClass.age}")
    simpleClass.eat()
  }

}

class SimpleClass {

  val name: String = "spark"
  var age: Int = _

  def eat(): Unit = {
    println(s"$name eat")
  }
}
  • new $類名,呼叫的是此類的構造器,由於每個類都會預設一個空構造器,所以可以省略類名後面的括號。
  • 從上面反編譯可以看出來, 對 象 . 物件. .屬性_ e q ( eq( eq(資料)相當於Java中的set,可以把資料傳輸到這個物件的屬性當中。

3. 構造器的使用

  • Scala中的構造器分為主構造器、附屬構造器
  • 主構造器:定義方式:class $類名(val $屬性名稱: $屬性型別),主構造器的定義是在Class後面來定義的,修飾符使用 val 來修飾,如果不使用 val 修飾符,物件則無法呼叫這個屬性。
  • 附屬構造器:def this($入參引數名: $入參引數型別),附屬構造器一般是呼叫其他的附屬構造器或者主構造器。
package com.xk.bigdata.scala.oo

object ConstructApp {

  def main(args: Array[String]): Unit = {
    val person = new Person("hadoop", 21, "A")
    println(person.school)
  }

  class Person(val name: String, val age: Int) {
    var school: String = _

    def this(name: String, age: Int, school: String) {
      this(name, age)
      this.school = school
    }
  }

}

4. 繼承的使用

  • 在Scala中使用繼承和Java中是一樣,使用extends關鍵字,Java中Class只有單繼承,介面可以多繼承,而Scala中可以多繼承,Scala 的trait 類似於Java中的介面,無論是trait還是子類,都是通過 extends + with 來實現,實現類或者介面數量大於三個,並且類或者trait通過先後順序進行載入。
  • 如果需要重寫父類的屬性或者方法,需要在屬性或者方法前面加上 override 關鍵字。
  • new 一個子類一定會先載入父類的構造器,然後載入子類的構造器。
package com.xk.bigdata.scala.oo

object ExtendsApp {

  def main(args: Array[String]): Unit = {
    val student = new Student("spark", 15, "A")
    student.eat()
    println(student.gender)
  }

  class Person(val name: String, val age: Int) {
    val gender = "M"

    def eat(): Unit = {
      println(s"Person Class $name........eat")
    }
  }

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

    override val gender: String = "L"

    override def eat(): Unit = {
      println(s"Student Class $name........eat")
    }
  }
}

5. 抽象類

  • 抽象類定義的時候需要有一個或者多個沒有實現的方法,只是定義了方法,沒有具體實現。
  • 抽象類只需要類名前面加 abstract 關鍵詞,屬性以及方法前面不需要新增 abstract 關鍵詞。
  • 抽象類使用: 1) 顯示定義 2)匿名子類
package com.xk.bigdata.scala.oo

object AbstractClassApp {

  def main(args: Array[String]): Unit = {
    // 通過顯示定義子類
    val student = new Student("hadoop", 20)
    student.speak
    // 匿名子類
    val student2 = new Person("spark", 21) {
      override def speak: Unit = {
        println(s"$name is speak")
      }
    }
    student2.speak
  }

  abstract class Person(val name: String, val age: Int) {
    def speak: Unit
  }

  class Student(name: String, age: Int) extends Person(name, age) {
    override def speak: Unit = {
      println(s"$name is speak")
    }
  }

}

6. Trait

  • Scala 中 Trait 相當於Java中的介面,不同於介面的地方是,Trait 還可以定義屬性和方法,一般情況下,Scala只能繼承單一父類,但是可以繼承多個 Trait,從結果來看,Scala實現了多重繼承。
  • Trait 定義方式:使用 trait 關鍵詞。
  • Trait 多重繼承通過 extends 和 with 關鍵詞來進行繼承。
package com.xk.bigdata.scala.oo

object TraitApp {

  def main(args: Array[String]): Unit = {
    val miUSB = new MiUSB
    println(miUSB.name)
    miUSB.plugIn
    miUSB.insert
    miUSB.working
  }

  trait USB {
    println("========USB======")
    val name: String

    def insert

    def working

    def pop
  }

  trait Logger {
    println("========Logger======")

    def loginfo
  }

  trait Socket {
    println("========Socket======")

    def plugIn
  }

  class MiUSB extends Logger with USB with Socket {
    override def loginfo: Unit = {
      println("loginfo=====>MiUSB")
    }

    override val name: String = "小米充電器"

    override def insert: Unit = {
      println("接入充電器")
    }

    override def working: Unit = {
      println("充電器開始工作")
    }

    override def pop: Unit = {
      println("充電完成,拔出!!")
    }

    override def plugIn: Unit = {
      println("插上插座")
    }
  }

}

7. Case Class

  • Case Class 和 Class 的區別:
    • 初始化的時候可以不用new,也可以加上,但是普通類必須加new。
    • 預設實現了equals、hashCode方法。
    • 預設是可以序列化的,實現了Serializable。
    • 自動從scala.Product中繼承一些函式。
    • case class 建構函式引數是public的,我們可以直接訪問。
    • case class預設情況下不能修改屬性值。
    • case class最重要的功能,支援模式匹配,這也是定義case class的重要原因
  • Case Class 和 Class 最大的區別就是 Case Class 重寫了 equals、hashcode、tostring方法。
  • 重寫 equals和hashcode 最大的表現就是兩個屬性值一樣的物件是相等的,說明 Case Class 底層判斷兩個物件是否相等,判斷的是物件裡面的每個屬性資料是否相等。
  • 重寫 tostring 表現在 列印 Case Class 物件的時候打印出來的出現數據,列印 Class 物件的資訊,列印的是記憶體地址。
  • 當使用 case class 的時候,Scala 會幫我們做如下幾個事情:
    • 構造器中的引數如果不被宣告為var的話,它預設的話是val型別的,但一般不推薦將構造器中的引數宣告為var。
    • 自動建立伴生物件,同時在裡面給我們實現子apply方法,使得我們在使用的時候可以不直接顯示地new物件。
    • 伴生物件中同樣會幫我們實現unapply方法,從而可以將case class應用於模式匹配。
    • 實現自己的toString、hashCode、copy、equals方法。
package com.xk.bigdata.scala.oo

object CaseClassApp {

  def main(args: Array[String]): Unit = {
    val person1 = new Person1("hadoop", 18)
    val person2 = new Person1("hadoop", 18)
    println(person1.toString)
    println(person1 == person2)
    val person3 = Person2("hadoop", 18)
    val person4 = Person2("hadoop", 18)
    println(person3.toString)
    println(person3 == person4)
  }

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

  case class Person2(name: String, age: Int)

}

8. Class 和 Object

  • Class 和 Object 的關係:
    • 物件不能帶引數,類可以。
    • 物件可以和類名一樣時,object被稱為伴生物件,class被稱為伴生類。
    • 類和伴生物件可以相互訪問其私有屬性,但是它們必須在一個原始檔當中。
    • 類只會被編譯,不會被執行。要執行,必須在Object中。
  • Class 和 Object 的區別:
    • Class 在呼叫的時候需要 new 一個物件,通過物件去呼叫Class裡面的屬性或方法。
    • Object 在呼叫的時候不需要 new 一個物件,可以直接呼叫 Object裡面的屬性和方法。
  • 同一個包下面的、名稱相同的 Class 和 Object 互為伴生,Class為Object的伴生類, Object 為 Class 的伴生物件。
  • 在呼叫伴生物件的後面加上括號,相當於呼叫伴生物件裡面的 apply 方法,通常可以在 apply 方法裡面 new 一個伴生類。
  • 如果想一口氣得到伴生類裡面的所有屬性,可以通過伴生物件的 unapply 方法來得到所有的屬性。
package com.xk.bigdata.scala.oo

object ClassObjectApp {

  def main(args: Array[String]): Unit = {
    // 呼叫伴生類
    val person1 = new Person("hadoop", 21)
    person1.eat()
    // 呼叫伴生物件
    val person2 = Person("hadoop", 21)
    person2.eat()
    // 呼叫伴生物件的 unapply 方法
    val Person(name, age) = Person("hadoop", 21)
    println(s"name:$name==========age:$age")
  }

}

object Person {
  def apply(name: String, age: Int): Person = {
    println("呼叫 object Person 的 apply 方法")
    new Person(name, age)
  }

  def unapply(arg: Person): Option[(String, Int)] = {
    println("呼叫 object Person 的 unapply 方法")
    Option(arg.name, arg.age)
  }
}

class Person(val name: String, val age: Int) {
  def eat(): Unit = {
    println(s"$name is eat")
  }
}

9. Case Class 和 Case Object

  • Case Class 、 Case Object 的區別:
    • 類中有參和無參,當類有引數的時候,用case class ,當類沒有引數的時候那麼用case object。
package com.xk.bigdata.scala.oo

object CaseClassCaseObjectApp {
  def main(args: Array[String]): Unit = {
    // 呼叫 case class eat
    val person1 = new Per("hadoop", 18)
    person1.eat()
    // 呼叫 case object eat
    Per.eat()
  }
}

case class Per(name: String, age: Int) {
  def eat(): Unit = {
    println("case class Person eat")
    println(s"$name is eat")
  }
}

case object Per {
  def eat(): Unit = {
    println("case object Person eat")
    println("eat")
  }
}