6. Scala面向對象編程(基礎部分)

6.1 基本介紹 

  6.1.1 Scala語言是面向對象的

      1) Java時面向對象的編程語言,因爲歷史緣由,Java中海存在着非面向對象的內容:基本類型,null,靜態方法等java

      2) Scala語言來自於Java,因此天生就是面向對象的語言,並且Scala時純粹的面相對象的語言,即在Scala中,一切皆爲對象程序員

      3) 在面向對象的學習過程當中能夠對比着Java語言學習面試

  6.1.2 類和對象的區別和聯繫 

      1) 類是抽象的,概念的表明一類事物,好比人類,貓類...編程

      2) 對象是具體的,實際的,表明一個具體事物框架

      3) 類是對象的模版,對象是類的一個個體,對應一個實例編程語言

      4) Scala中類和對象的區別和聯繫和Java是同樣的ide

  6.1.3 如何定義類 

      -基本語法函數式編程

        [修飾符] class 類名 {函數

          類體工具

        }

      -定義類的注意事項

        1) Scala語法中,類並不聲明爲public,全部這些類都具備公有可見性(默認就是public)

        2) 一個Scala源文件能夠包含多個類,並且默認都是public

  6.1.4 屬性 

      -基本介紹

        屬性是類的一個組成部分,通常是值數據類型,也但是引用類型

      -案例演示

class Dog {
  var name = "Tom"
  var lover = new Fish

}

class Fish {
  
}

  6.1.5 屬性/成員變量 

      -注意事項和細節說明

       1) 屬性的定義語法同變量,示例:[訪問修飾符] var 屬性名稱 [: 類型] = 屬性值

       2) 屬性的定義類型能夠爲任意類型,包含值類型或引用類型

       3) Scala中聲明一個屬性,必須顯示的初始化,而後根據初始化數據的類型自動推斷,屬性類型能夠省略(這點和Java不一樣)

       4) 若是賦值爲null,則必定要加類型,由於不加類型,那麼該屬性的類型就是Null類型

       5) 若是在定義屬性時,暫時不賦值,也可使用符號_(下劃線),讓系統分配默認值

       

class A {
  var a1: String = _ //null
  var a2: Byte = _ // 0
  var a3: Double = _ // 0.0
  var a4: Boolean = _ // false
}

  6.1.6 屬性的高級部分 

      說明:屬性的高級部分和構造器(構造方法/函數)相關,具體介紹將在構造器部分詳解

  6.1.7 如何建立對象 

      -基本語法

      val | var 對象名 [: 類型] = new 類型()

      -說明

      1) 若是咱們不但願改變對象的引用(即:內存地址),應該聲明爲val性質的,不然聲明爲var,Scala設計者推薦使用val,由於通常來講,在程序中,咱們只是改變對象屬性的值,而不是改變對象的引用

      2) Scala在聲明對象變量時,能夠根據建立對象的類型自動推斷,因此類型聲明能夠省略,但當類型和後面new對象類型有繼承關係時即多態,就必須寫了

      3) 案例演示

object boke_demo01 {
  
  def main(args: Array[String]): Unit = {
    val emp = new Emp // emp 類型就是Emp
    //若是咱們但願將子類對象,交給父類的引用,這時就須要寫上類型
    val emp2: Person = new Emp

  }
}

class Person {

}

class Emp extends Person {
  
}

  6.1.8 類和對象的內存分配機制 

      -案例演示

object boke_demo01 {

  def main(args: Array[String]): Unit = {
    val p1 = new Person2
    p1.name = "jack"
    p1.age = 10

    val p2 = p1
    println(p1 == p2) // true
    p1.name = "tom"
    println("p2.name=" + p2.name) // p2.name=tom
  }

}

class Person2 {
  var name = ""
  var age: Int = _ //若是是用 _ 方式給默認值,則屬性必須指定類型
}

      -案例演示對應的內存佈局圖

6.2 方法 

  6.2.1 基本說明 

      Scala中的方法其實就是函數,聲明規則請參考函數式編程中的函數聲明

  6.2.2 基本語法 

      def 方法名[: 返回值類型] = {

        方法體

      }

  6.2.3 方法案例演示 

      給Cat類添加cal方法,能夠計算兩個數的和

object MethodDemo01 {
  def main(args: Array[String]): Unit = {
    val cat = new Cat
    println(cat.cal(10, 20))
  }
}

class Cat {
  private var sal: Double = _
  var food: String = _

  //方法
  def cal(n1: Int, n2: Int): Int = {
    return n1 + n2
  }
}

6.3 構造器 

  6.3.1 看一個需求 

      咱們來看一個需求:前面咱們在建立Person的對象時,是先把一個對象建立好後,再給他的姓名和年齡屬性賦值,若是如今要求,在建立Person類對象時,就直接制定這個對象的姓名和年齡,該怎麼作?這時就可使用構造方法/構造器

  6.3.2 回顧-Java構造器基本語法 

      [修飾符] 方法名 (參數列表) {

        構造方法體

      }

  6.3.3 回顧-Java構造器的特色 

      1) 在Java中一個類能夠定義多個不一樣的構造方法,構造方法重載

      2) 若是程序員沒有定義構造方法,系統會自動給類生成一個無參構造方法(也叫默認構造器),好比:Person(){}

      3) 一旦定義了本身的構造方法(構造器),默認的構造方法就覆蓋了,就不能使用默認的無參構造方法,除非顯示的定義一下,即:Person(){}

  6.3.4 Java構造器案例 

      在前面定義的Person類中添加兩個構造器

      第一個無參構造器:利用構造器設置全部人的age屬性初始值都爲18

      第二個帶name和age兩個參數的構造器:使得每次建立Person對象的同時初始化對象的name屬性值和age屬性值

public class Person {

    public String name;
    public int age;

    public String getInfo() {
        return name + "\t" + age;
    }

    public Person() {
        age = 18;
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

}

  6.3.5 Scala構造器的介紹

      和Java同樣,Scala構造對象也須要調用構造方法,而且能夠有任意多個構造方法(即Scala中構造器也支持重載),Scala類的構造器包括:主構造器和輔助構造器

  6.3.6 Scala構造器的基本語法 

      class 類名(形參列表) {  //主構造器

        def this(形參列表){  //輔助構造器

        }

        def this(形參列表){  //輔助構造器能夠有多個...

        }

      }

      輔助構造器的函數名this,能夠有多個,編譯器經過不一樣參數來區分

  6.3.7 Scala構造器的快速入門 

      建立Person對象的同時初始化對象的name屬性和age屬性,案例演示

object boke_demo01 {

  def main(args: Array[String]): Unit = {
    //    val p1 = new Person("Jack", 20)
    //    println(p1)

    //下面這句話就會調用def this(name:String)
    val p2 = new Person("Tom")
    println(p2)
  }
}

//構造器的快速入門
//建立Person對象的同時初始化對象的age屬性值和name屬性值
class Person(inName: String, inAge: Int) {
  var name: String = inName
  var age: Int = inAge
  age += 10
  println("~~~~~~~~~~")

  //重寫了toString,便於輸出對象的信息
  override def toString: String = {
    "name=" + this.name + "\t age" + this.age
  }

  println("ok~~~~~")
  println("age=" + age)

  def this(name: String) {
    //輔助構造器,必須在第一行顯式調用主構造器(能夠是直接,也能夠是間接)
    this("Jack", 10)
    //this
    this.name = name //從新賦值
  }
}

  6.3.8 Scala構造器注意事項和細節說明 

      1) Scala構造器的做用是完成對新對象的初始化,構造器沒有返回值

      2) 主構造器的聲明直接放置於類名以後

      3) 主構造器會執行類定義中的全部語句,這裏能夠體會到Scala的函數式編程和麪向對象編程融合在一塊兒,即:構造器也是方法(函數),傳遞參數和使用方法和前面的函數部份內容沒有區別

      4) 若是主構造器沒有參數,小括號能夠省略,構建對象時調用的構造方法的小括號也能夠省略

class AA {

}

val a = new AA
val b = new AA()

      5) 輔助構造器名稱爲this(這個和Java是不同的),多個輔助構造器經過不一樣參數列表進行區分,在底層就是構造器重載

object boke_demo01 {

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

    val p1 = new Person2("jack")
    p1.showInfo()
  }
}

//定義了一個Person類
//Person 有幾個構造器 4
class Person2 private() {
  var name: String = _
  var age: Int = _

  def this(name: String) {
    //輔助構造器不管是直接或間接,最終都必定要調用主構造器,執行主構造器的邏輯
    //並且須要放在輔助構造器的第一行[這點和java同樣,java中一個構造器要調用同類的其它構造器,也須要放在第一行]
    this() //直接調用主構造器
    this.name = name
  }

  //輔助構造器
  def this(name: String, age: Int) {
    this() //直接調用主構造器
    this.name = name
    this.age = age
  }

  def this(age: Int) {
    this("匿名") //調用主構造器,由於 def this(name : String) 中調用了主構造器!
    this.age = age
  }

  def showInfo(): Unit = {
    println("person信息以下:")
    println("name=" + this.name)
    println("age=" + this.age)
  }
}

      6) 若是想要主構造器編程私有的,能夠在()以前加上private,這樣用戶只能經過輔助構造器來構造對象了,好比: class Person2 private(){}

      7) 輔助構造器的聲明不能和主構造器的聲明一致,會發生錯誤(即構造器名重複)

6.4 屬性高級

      對屬性的內容作一個增強

  6.4.1 構造器參數 

      1) Scala類的主構造器的形參未用任何修飾符修飾,那麼這個參數是局部變量

      2) 若是參數使用val關鍵字聲明,那麼Scala會將參數做爲類的私有隻讀屬性使用

      3) 若是參數使用var關鍵字聲明,那麼Scala會將參數做爲類的成員屬性使用,並會提供對應的xxx()[相似getter]/xxx_$eq()[相似setter]方法,即這時的成員屬性是私有的,可是可讀寫

      4) 案例演示 

object boke_demo01 {

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

    val worker = new Worker("smith")
    worker.name //不能訪問 inName

    val worker2 = new Worker2("smith2")
    worker2.inName  //能夠訪問 inName
    println("hello!")

    val worker3 = new Worker3("jack")
    worker3.inName = "mary"
    println(worker3.inName)
  }
}

//若是 主構造器是Worker(inName: String) ,那麼 inName就是一個局部變量
class Worker(inName: String) {
  var name = inName
}
//若是 主構造器是Worker2(val inName: String) ,那麼 inName就是Worker2的一個private的只讀屬性
class Worker2(val inName: String) {
  var name = inName
}

// 若是 主構造器是Worker3(var inName: String) ,那麼 inName就是Worker3的一個
// 一個private 的能夠讀寫屬性
class Worker3(var inName: String) {
  var name = inName
}

  6.4.2 Bean屬性 

      JavaBean規範定義了Java的屬性是像getXxx()和setXxx()方法。許多Java工具(框架)都依賴這個命名習慣。爲了Java的互操做性。將Scala字段加@BeanProperty時,這樣會自動生成規範的setXxx/getXxx方法。這時可使用 對象.setXxx()和 對象.getXxx()來調用屬性

      注意:給某個屬性加入@BeanPropetry註解後,會生成getXxx和setXxx的方法,而且對原來底層自動生成相似xxx(),xxx_$eq()方法,沒有衝突,兩者能夠共存

import scala.beans.BeanProperty

object boke_demo01 {

  def main(args: Array[String]): Unit = {
    val car = new Car
    car.name = "寶馬"
    println(car.name)

    //使用 @BeanProperty 自動生成 getXxx 和 setXxx
    car.setName("奔馳")
    println(car.getName())
  }
}

class Car {
  @BeanProperty var name: String = null
}

6.5 Scala對象建立的流程分析 

  6.5.1 看一個案例  

class Person {
  var age: Short = 90
  var name: String = _

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

}

var p: Person = new Person ("小倩", 20)

  6.5.2 流程分析(面試題-寫出) 

      1) 加載類的信息(屬性信息,方法信息)

      2) 在內存中(堆)開闢空間

      3) 使用父類的構造器(主和輔助)進行初始化

      4) 使用主構造器對屬性進行初始化[age:90, name:null]

      5) 使用輔助構造器對屬性進行初始化[age:20, name:小倩]

      6) 將開闢的對象的地址賦給p這個引用

相關文章
相關標籤/搜索