Scala--面向物件
阿新 • • 發佈:2021-01-26
目錄
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")
}
}