【Scala】類和對象的介紹與使用

目錄

類和對象

創建類和對象

定義和訪問成員變量

使用下劃線初始化成員變量

定義成員方法

訪問修飾符

類的構造器

主構造器

輔助構造器

單例對象

在單例對象中定義成員方法

main方法

實現App Trait來定義入口

伴生對象

private[this]訪問權限

繼承

override和super

類型判斷

isInstanceOf/asInstanceOf

getClass/classOf

抽象類

匿名內部類

特質(trait)

繼承單個特質

繼承多個特質

object繼承trait

使用trait實現模板模式

對象混入trait

trait實現調用鏈模式

trait繼承class

樣例類

常用方法

樣例對象


  • 類和對象

scala是支持面向對象的,也有類和對象的概念。我們依然可以基於scala語言來開發面向對象的應用程序。

 

 

  • 創建類和對象

使用class來定義一個類 new來創建對象

 

例:

object demo01 {

  //創建類
  class user{}
  
  def main(args: Array[String]): Unit = {
      //創建對象
      var u = new user()
      println("hello word")
  }
}

 

  • 定義和訪問成員變量

一個類會有自己的屬性,例如:人這樣一個類,有自己的姓名和年齡。在類中定義、和訪問成員變量

 

例:

object demo01 {
  //創建類
  class user{
    // 定義成員變量
    val id = "123"
    var name = ""
    var age = 0
  }

  def main(args: Array[String]): Unit = {
      //創建對象
      var u = new user()
      u.name = "zhangsan"
      u.age = 20

      //獲取變量值
      println(u.id)
      println(u.name)
      println(u.age)
  }
}

 

  • 使用下劃線初始化成員變量

1.在定義var類型的成員變量時,可以使用_來初始化成員變量

2.使用下劃線初始化,成員變量必須爲var(變量),並且要指定數據類型

 

例:

object demo01 {

  //創建類
  class user{
    // 定義成員變量 使用下劃線進行初始化
    var id:String =  _
    var name:String = _
    var age:Int = _
  }

  def main(args: Array[String]): Unit = {
      //創建對象
      var u = new user()
      u.name = "zhangsan"
      u.age = 20

      //獲取變量值
      println(u.id)
      println(u.name)
      println(u.age)
  }
}

 

  • 定義成員方法

類可以有自己的行爲,scala中也可以通過定義成員方法來定義類的行爲。使用def來定義成員方法

 

例:

object demo01 {
  //創建類
  class user{
    // 定義成員變量 使用下劃線進行初始化
    var id:String =  _
    var name:String = _
    var age:Int = _

    //定義成員方法
    def prints (msg:String): Unit = {
      println(msg + " hello")
    }
  }

  def main(args: Array[String]): Unit = {
      //創建對象
      var u = new user()
      u.name = "zhangsan"
      u.age = 20
    
      //輸出成員方法
       u.prints("zhangsan")
  }
}

 

  • 訪問修飾符

1.和Java一樣,scala也可以通過訪問修飾符,來控制成員變量和成員方法是否可以被訪問。

2.可以在成員前面添加private/protected(私有的/受保護的)關鍵字來控制成員的可見性。

3.scala中,沒有public關鍵字,任何沒有被標爲private或protected的成員都是公共的

 

例:

object demo02 {
  class Persion {
    //定義成變量
    private var name: String = ""
    private var age: Int = 0

    //定義成員方法
    def getName() = {
      this.name
    }

    def setName(name: String): Unit = {
      this.name = name
    }

    def getAge() = {
      this.age
    }

    def setAge(age: Int): Unit = {
      this.age = age
    }

    private def getNameAndAge() = {
      this.getName() + "  " + this.getAge()
    }

  }
  
  def main(args: Array[String]): Unit = {
    //實例化對象
    var persion = new Persion();

    //調用方法
    persion.setName("zhangsan")
    persion.setAge(200)

    println(persion.getName())
    println(persion.getAge())
  }
}

 

  • 類的構造器

1.當創建類對象的時候,會自動調用類的構造器。之前使用的都是默認構造器

2.Scala的構造器分爲主構造器與輔助構造器

3.主構造器:直接在class括號內添加屬性

4.輔助構造器:除了主構造器之外的都是輔助構造器

 

主構造器

1.主構造器的參數列表是直接定義在類名後面,添加了val/var表示直接通過主構造器定義成員變量

2.構造器參數列表可以指定默認值

3.創建實例,調用構造器可以指定字段進行初始化

4.整個class中除了字段定義和方法定義的代碼都是構造代碼

格式:

class 類名(var/val 參數名:類型 = 默認值, var/val 參數名:類型 = 默認值){
   // 構造代碼塊
}

例:

object demo03 {
  //創建構造器
  class Person(var name:String = "",var age:Int = 0){

  }

  def main(args: Array[String]): Unit = {
    var p = new Person("zhangsan",17)
    println(p.name)
    println(p.age)
  }
}

 

輔助構造器

1.除了主構造器之外的構造器稱爲輔助構造器。

2.定義輔助構造器與定義方法一樣,也使用def關鍵字來定義

3.這個方法的名字爲this

4.輔助構造器的第一行代碼,必須要調用主構造器或者其他輔助構造器

格式:

def this(參數名:類型, 參數名:類型) {
    // 第一行需要調用主構造器或者其他構造器
    // 構造器代碼
}

例:

object demo03 {
  //創建構造器
  class Person(var name:String = "",var address:String =  ""){

      //創建輔助構造器
      def this(arr:Array[String]){
        this(arr(0),arr(1))
      }
  }

  def main(args: Array[String]): Unit = {
      //實例化對象
      var p = new Person(Array("zhangsan","北京"))
      println(p.name)
      println(p.address)
  }
}

 

  • 單例對象

1.scala中沒有Java中的靜態成員,若想要定義類似於Java的static變量、static方法,就要使用到scala中的單例對象——object.

2.單例對象表示全局僅有一個對象(類似於Java static概念)

3.定義單例對象和定義類很像,就是把class換成object

4.在object中定義的成員變量類似於Java的靜態變量

5.可以使用object直接引用成員變量

 

例:

object demo04 {
  //創建單例對象
  object Person {
    var name: String = "zhangsan"
  }

  def main(args: Array[String]): Unit = {
    println(Person.name)
  }
}

 

在單例對象中定義成員方法

1.在object中定義的成員方法類似於Java的靜態方法

例:

object demo04 {
  //創建單例對象
  object Person {
    var name: String = "zhangsan"

    //定義成員方法
    def show() = {
      println("show")
    }
  }

  def main(args: Array[String]): Unit = {
    println(Person.name)

    //調用方法
    Person.show()
  }
}

 

  • main方法

scala和Java一樣,如果要運行一個程序,必須有一個main方法。在Java中main方法是靜態的,而在scala中沒有靜態方法。在scala中,這個main方法必須放在一個單例對象中。

 

格式:

def main(args:Array[String]):Unit = {
    // 方法體
}

 

實現App Trait來定義入口

創建一個object,繼承自App Trait(特質),然後將需要編寫在main方法中的代碼,寫在object的構造方法體內。

 格式:

object 單例對象名 extends App {
    // 方法體
}

例:

object demo05 extends App {
    println("holle")
}

 

  • 伴生對象

1.一個class和object具有同樣的名字。這個object稱爲伴生對象,這個class稱爲伴生類

2.伴生對象必須要和伴生類一樣的名字

3.伴生對象和伴生類在同一個scala源文件中

4.伴生對象和伴生類可以互相訪問private屬性

 

例:

object demo06 {
  class Person{
    private val id:String = "123"

    //可以互相訪問私有數據
    println(Person.name)
  }

  object Person{
    private var name:String = "zhangsan"

    //可以互相訪問私有數據
    println(new Person().id)
  }

  def main(args: Array[String]): Unit = {

  }
}

 

private[this]訪問權限

如果某個成員的權限設置爲private[this],表示只能在當前類中訪問。伴生對象也不可以訪問

例:

object demo06 {
  class Person{
    private[this] val id:String = "123"

    //可以互相訪問私有數據
    println(Person.name)
  }

  object Person{
    private var name:String = "zhangsan"

    //被private[this]修飾 不能訪問 報錯 
    //println(new Person().id)
  }

  def main(args: Array[String]): Unit = {

  }
}

 

  • 繼承

1.scala語言是支持面向對象編程的, 可以使用scala來實現繼承,通過繼承來減少重複代碼

2.使用extends關鍵字來實現繼承

3.可以在子類中定義父類中沒有的字段和方法,或者重寫父類的方法

4.類和單例對象都可以從某個父類繼承

 

格式:

class/object 子類 extends 父類 {
    ..
}

 

例:

//父類
class Person {
  var name:String = "zhangsan"
  def getName(): Unit ={
    this.name
  }
}

object demo07 {
    //子類
    class  Stu extends Person{

    }

  def main(args: Array[String]): Unit = {
    var stu = new Stu();
    //調用父類的方法
    println(stu.name)
  }
}

 

  • override和super

1.類似於Java語言, 在子類中使用override需要來重寫父類的成員,可以使用super來引用父類

2.子類要覆蓋父類中的一個方法,必須要使用override關鍵字

3.使用override來重寫一個val字段

4.使用super關鍵字來訪問父類的成員方法

 

例:

//父類
class Person {
  val name = "super"
  def getName = name
}

object demo07 {

  class Student extends Person {
    // 重寫val字段
    override val name: String = "child"
    // 重寫getName方法
    override def getName: String = "hello, " + super.getName
  }


  def main(args: Array[String]): Unit = {
    var stu = new Student();
    println(stu.name)
    println(stu.getName)
  }
}

 

 

  • 類型判斷

有時候,我們設計的程序,要根據變量的類型來執行對應的邏輯

 

 

isInstanceOf/asInstanceOf

1.isInstanceOf判斷對象是否爲指定類以及其子類的對象

2.asInstanceOf將對象轉換爲指定類型

格式:

// 判斷對象是否爲指定類型
val trueOrFalse:Boolean = 對象.isInstanceOf[類型]

// 將對象轉換爲指定類型
val 變量 = 對象.asInstanceOf[類型]

例:

//父類
class Person {
  val name = "super"
  def getName = name
}

object demo07 {

    //子類
  class Student extends Person {
    // 重寫val字段
    override val name: String = "child"
    // 重寫getName方法
    override def getName: String = "hello, " + super.getName
  }


  def main(args: Array[String]): Unit = {
      var stu1 = new Student();
      var stu2:Person = new Student();

      //判斷對象是否爲指定類型 true
      println(stu1.isInstanceOf[Student])

      //將對象轉換爲指定類型 將Person類型轉爲Student類型
      if (stu2.isInstanceOf[Student]){
        val s2 = stu2.asInstanceOf[Student]
        println(s2)
      }

  }
}

 

getClass/classOf

1.isInstanceOf 只能判斷對象是否爲指定類以及其子類的對象,而不能精確的判斷出,對象就是指定類的對象。如果要求精確地判斷出對象就是指定類的對象,那麼就只能使用 getClass 和 classOf 。

2.p.getClass可以精確獲取對象的類型(不是父類)

3.classOf[x] 可以指定精確類型

4.使用==操作符可以直接比較類型

例:

class Person {
  val name = "super"
  def getName = name
}

object demo07 {

  class Student extends Person {
    // 重寫val字段
    override val name: String = "child"
    // 重寫getName方法
    override def getName: String = "hello, " + super.getName
  }


  def main(args: Array[String]): Unit = {
      var stu = new Student();

      //true
      println(stu.getClass() == classOf[Student])

      //false//抽象類
abstract class Shape {
  //抽象字段
  var r:Double

  //抽象方法
  def area(): Double
}

//子類1 正方形
class Square(edge: Double) extends Shape {
  //實現字段
  override var r: Double =  edge;

  //實現方法
  override def area(): Double = {
    r * r
  }

}

//子類2 圓形
class Roundness(radius: Double) extends Shape {
  //實現字段
  override var r: Double = radius

  //實現方法
  override def area(): Double = {
    r * r * 3.14
  }

}

def main(args: Array[String]): Unit = {
  //正方形
  var square = new Square(10);
  println(square.area())

  //圓形
  var roundness = new Roundness(10);
  println(roundness.area())

}
      println(stu.getClass() == classOf[Person])
  }
}

 

  • 抽象類

1.如果類的某個成員在當前類中的定義是不包含完整的,它就是一個抽象類

2.不完整定義有兩種情況:

                                         a.方法沒有方法體(抽象方法)

                                         b.變量沒有初始化(抽象字段)

3.定義抽象類和Java一樣,在類前面加上abstract關鍵字

4.在抽象類中不抽象的字段或方法不用重寫

 

格式:

// 定義抽象類
abstract class 抽象類名 {
  // 定義抽象字段
  val 抽象字段名:類型
  // 定義抽象方法
  def 方法名(參數:參數類型,參數:參數類型...):返回類型
}

 

例:

//抽象類
abstract class Person {
  //抽象字段
  var name: String
  //抽象方法
  def Say(msg:String):String
}
//抽象類
abstract class Shape {
  //抽象字段
  var r:Double

  //抽象方法
  def area(): Double
}

//子類1 正方形
class Square(edge: Double) extends Shape {
  //實現字段
  override var r: Double =  edge;

  //實現方法
  override def area(): Double = {
    r * r
  }

}

//子類2 圓形
class Roundness(radius: Double) extends Shape {
  //實現字段
  override var r: Double = radius

  //實現方法
  override def area(): Double = {
    r * r * 3.14
  }

}

//main方法
def main(args: Array[String]): Unit = {
  //正方形
  var square = new Square(10);
  println(square.area())

  //圓形
  var roundness = new Roundness(10);
  println(roundness.area())

}

 

  • 匿名內部類

匿名內部類是沒有名稱的子類,直接用來創建實例對象。Spark的源代碼中有大量使用到匿名內部類。scala中的匿名內部類使用與Java一致。

 

格式:

val/var 變量名 = new 類/抽象類 {
    // 重寫方法
}

 

例:

//抽象類
abstract class Shape {
  //抽象字段
  var r: Double

  //抽象方法
  def area(): Double
}

//main方法
def main(args: Array[String]): Unit = {

    //匿名內部類
    var dd = new Shape {
      //重寫字段
      override var r: Double = 10
      //重寫方法
      override def area(): Double = {
          r
      }
    }

    //打印
    println(dd.area)
    
  }
}

 

  • 特質(trait)

1.scala中沒有Java中的接口(interface),替代的概念是特質

2.特質是scala中代碼複用的基礎單元

3.它可以將方法和字段定義封裝起來,然後添加到類中

4.與類繼承不一樣的是,類繼承要求每個類都只能繼承一個超類,而一個類可以添加任意數量的特質。

5.特質的定義和抽象類的定義很像,但它是使用trait關鍵字

6.使用extends來繼承trait(scala不論是類還是特質,都是使用extends關鍵字)

7.如果要繼承多個trait,則使用with關鍵字

8.在trait中可以定義具體字段和抽象字段

9.scala中可以將trait混入到對象中,就是將trait中定義的方法、字段添加到一個對象中

10.trait也可以繼承class的。特質會將class中的成員都繼承下來

 

格式:

//定義特質
trait 名稱 {
    // 抽象字段
    // 抽象方法
}

//繼承特質
class 類 extends 特質1 with 特質2 {
    // 字段實現
    // 方法實現
}

 

繼承單個特質

例:

//特質
trait Person {
  //完整字段 不需要被繼承
  var id: String = "123456"

  //抽象字段
  var name: String

  //完整方法 不需要被繼承
  def SayHello(msg: String) = {
    println(msg)
  }

  //抽象方法
  def Say(): String


}

//子類
class Stuent extends Person {
  //實現父類字段
  override var name: String = "張三"
  //實現父類方法
  override def Say(): String = {
    name
  }
}

 

繼承多個特質

例:

//特質1
trait Person1 {
  //完整字段 不需要被繼承
  var id: String = "123456"

  //抽象字段
  var name: String

  //完整方法 不需要被繼承
  def SayHello(msg: String) = {
    println(msg)
  }

  //抽象方法
  def Say(): String
}

//特質2
trait Person2 {
  //抽象方法
  def doing(): String
}

//子類 繼承Person1 Person2兩個特質
class Student extends Person1 with Person2 {
  //實現父類Person1字段
  override var name: String = "張三"

  //實現父類Person1方法
  override def Say(): String = {
    name
  }

  //實現父類Person2方法
  override def doing(): String = {
    name
  }
}

 

object繼承trait

例:

//特質
trait Sum2 {
  //抽象方法
  def sum(num1: Int, num2: Int): Unit
}

//子object
object Sums extends Sum2 {
   //重寫方法
  override def sum(num1: Int, num2: Int): Unit = {
    println(num1 + num2)
  }
}

//main方法
def main(args: Array[String]): Unit = {
  //調用方法  
  Sums.sum(10,10)
}

 

使用trait實現模板模式

在一個特質中,具體方法依賴於抽象方法,而抽象方法可以放到繼承trait的子類中實現,這種設計方式也稱爲模板模式

例:

//特質
trait Logger {
  //抽象方法
  def log(msg: String): Unit

  //創建具體方法並調用抽象方法
  def info(msg: String) = log("Info" + msg)
  def warn(msg: String) = log("Warn" + msg)
  def error(msg: String) = log("Error" + msg)

}

//繼承特質
class ConsoleLogger extends Logger {

  //現抽象方法
  override def log(msg: String): Unit = {
    println(msg)
  }
}

def main(args: Array[String]): Unit = {
  var log =  new ConsoleLogger();

  //調用方法
  log.info("信息日誌")
  log.warn("警告日誌")
  log.error("錯誤日誌")
}

 

對象混入trait

scala中可以將trait混入到對象中,就是將trait中定義的方法、字段添加到一個對象中

格式:

val/var 對象名 = new 類 with 

例:

//特質
trait Do {
  def say(msg: String): String = {
    println(msg + "1")
    msg
  }

  def say1():String
}

//類
class Student

//main方法
def main(args: Array[String]): Unit = {
  //創建對象 混入trait
  var stu = new Student() with Do {
    //實現抽象方法
    override def say1(): String = {
      "lisi"
    }
  }

  //調用方法
  stu.say("zhangsan")
  println( stu.say1())
}

 

trait實現調用鏈模式

類繼承了多個trait後,可以依次調用多個trait中的同一個方法,只要讓多個trait中的同一個方法在最後都依次執行super關鍵字即可。類中調用多個tait中都有這個方法時,首先會從最右邊的trait方法開始執行,然後依次往左執行,形成一個調用鏈條。

例:

//特質1
trait HandlerTrait {

  def handler(msg: String) = {
    println("第四步:打印數據" + msg)
  }

}

//特質2 繼承特質1
trait DataValidHandlerTrait extends HandlerTrait {

  //重寫方法
  override def handler(msg: String): Unit = {
    println("第三步:驗證數據" + msg)

    //調用父類方法
    super.handler(msg)
  }

}

//特質3 繼承特質1
trait SignatureValidHandlerTrait extends HandlerTrait {

  //重寫方法
  override def handler(msg: String): Unit = {
    println("第二步:檢查簽名" + msg)

    //調用父類方法
    super.handler(msg)
  }

}

//子類 繼承特質1 特質2
class PaymentService extends DataValidHandlerTrait with SignatureValidHandlerTrait {
  def pay(msg: String) = {
    println("第一步:準備支付" + msg)
    super.handler(msg)
  }
}

//main方法
def main(args: Array[String]): Unit = {
  var paymentService = new PaymentService();
  paymentService.pay("牛奶")
}

 

trait繼承class

trait也可以繼承class的。特質會將class中的成員都繼承下來

//父類
class MyUtils {
  def printMsg(msg: String) = {
    println(msg)
  }

}

//子特質
trait Logger extends MyUtils {
  def log(msg: String) = printMsg(msg)
  
}

//特質的子類
class Person extends Logger {
  def Say(msg: String) = log(msg)
  
}

//main方法
def main(args: Array[String]): Unit = {
  var person = new Person();

  //調用方法  Person子類可以調用父類所有方法
  person.Say("zhangsan");
  person.log("lisi")
  person.printMsg("wangwu")
}

 

  • 樣例類

樣例類是一種特殊類,它可以用來快速定義一個用於保存數據的類(類似於Java POJO類),在後續要學習併發編程和spark、flink這些框架也都會經常使用它。

 

格式:

case class 樣例類名([var/val] 成員變量名1:類型1, 成員變量名2:類型2, 成員變量名3:類型3)

 

例:

//樣例類  默認的字段爲常量
case class Student(var name: String, age: Int) {

}

//main方法
def main(args: Array[String]): Unit = {

  //創建樣例類對象 不需要new
  var student = Student("張三", 17)

  //重賦值數據 如果數據爲變量(var)則可以重新賦值
  student.name = "李四"

  //打印數據
  println(student.name)
  println(student.age)
}

 

常用方法

apply:apply方法可以讓我們快速地使用類名來創建對象

toString:toString返回樣例類名稱(成員變量1, 成員變量2, 成員變量3....)

equals:樣例類自動實現了equals方法,可以直接使用==比較兩個樣例類是否相等,即所有的成員變量是否相等

hashCode:樣例類自動實現了hashCode方法,如果所有成員變量的值相同,則hash值相同,只要有一個不一樣,則hash值不一樣。

copy:樣例類實現了copy方法,可以快速創建一個相同的實例對象,可以使用帶名參數指定給成員進行重新賦值

 

  • 樣例對象

1.定義枚舉

2.作爲沒有任何參數的消息傳遞

 

格式:

case object 樣例對象名

 

例:

object Test02 {
  //特質
  trait sex

  //定義特質的枚舉
  case object Boy extends sex

  case object Girl extends sex

  //創建對象 對象的一個屬性設置爲枚舉
  case class Person(name: String, sex: sex)

  def main(args: Array[String]): Unit = {
    //創建對象
    var person = Person("張三", Boy)
  }

}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章