6.1 基本介紹 6.1.1 Scala語言是面向對象的 1) Java時面向對象的編程語言,由於歷史原因,Java中海存在著非面向對象的內容:基本類型,null,靜態方法等 2) Scala語言來自於Java,所以天生就是面向對象的語言,而且Scala時純粹的面相對象的語言,即在Scala中,一切 ...
6.1 基本介紹
6.1.1 Scala語言是面向對象的
1) Java時面向對象的編程語言,由於歷史原因,Java中海存在著非面向對象的內容:基本類型,null,靜態方法等
2) Scala語言來自於Java,所以天生就是面向對象的語言,而且Scala時純粹的面相對象的語言,即在Scala中,一切皆為對象
3) 在面向對象的學習過程中可以對比著Java語言學習
6.1.2 類和對象的區別和聯繫
1) 類是抽象的,概念的代表一類事物,比如人類,貓類...
2) 對象是具體的,實際的,代表一個具體事物
3) 類是對象的模版,對象是類的一個個體,對應一個實例
4) Scala中類和對象的區別和聯繫和Java是一樣的
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這個引用