1. 擴展類
- 擴展的方法是使用
extends
關鍵字
class Person {
var name = ""
}
class Employee extends Person {
var salary = 0.0
def description = "An employee with name " + name + " and salary " + salary
}
object Main extends App {
val fred = new Employee
fred.name = "Fred"
fred.salary = 50000
println(fred.description)
}
- 在類、方法或字段前加
final
關鍵字,這樣類或方法就不會被擴展或重寫。
2. 重寫方法
- Scala重寫一個非抽象方法,必須用
override
修飾符。
class Person {
var name = ""
override def toString = getClass.getName + "[name=" + name + "]"
}
class Employee extends Person {
var salary = 0.0
override def toString = super.toString + "[salary=" + salary + "]"
}
object Main extends App {
val fred = new Employee
fred.name = "Fred"
fred.salary = 50000
println(fred)
}
- 調用超類(父類),使用
super
關鍵字。
3. 類型檢查和轉換
isInstanceOf
方法,測試某個對象是否屬於某個給定類。asinstancdOf
方法,將引用轉換爲子類的引用。classOf
測試p是Employee對象但又不是子類。
class Person {
var name = ""
override def toString = getClass.getName + "[name=" + name + "]"
}
class Employee extends Person {
var salary = 0.0
override def toString = super.toString + "[salary=" + salary + "]"
}
class Manager extends Employee
object Main extends App {
val r = scala.math.random
val p = if (r < 0.33) new Person
else if (r < 0.67) new Employee
else new Manager
if (p.isInstanceOf[Employee]) {
val s = p.asInstanceOf[Employee] // s has type Employee
println("It's an employee.")
s.salary = 50000
if (p.getClass == classOf[Manager]) {
println("Actually, it's a manager")
s.salary *= 2
}
}
println(p)
}
4. 受保護字段和方法
將字段或方法聲明爲
protected
,這樣的成員可以被任意子類訪問,但不能從其他位置看到。protected的成員對類所屬的包是不可見的。
protected[this]
將訪問權限限定在當前對象。
5. 超類的構造
- 只有主構造器可以調用超類的構造器。
class Person(val name: String, val age: Int) {
override def toString = getClass.getName + "[name=" + name +
",age=" + age + "]"
}
class Employee(name: String, age: Int, val salary : Double) extends
Person(name, age) {
override def toString = super.toString + "[salary=" + salary + "]"
}
new Employee("Fred", 42, 50000)
6. 重寫字段
重寫有如下限制:
- def只重寫另一個def。
- val只能重寫另一個val或不帶參數的def。
- var只能重寫另一個抽象的var。
class Person(val name: String) {
override def toString = getClass.getName + "[name=" + name + "]"
}
class SecretAgent(codename: String) extends Person(codename) {
override val name = "secret" // 不暴露真名
override val toString = "secret" // ...或類名
}
val fred = new Person("Fred")
fred.name
val james = new SecretAgent("007")
james.name
// 用val重寫抽象類的def
abstract class Person {
def id: Int
}
class Student(override val id: Int) extends Person
class SecretAgent extends Person {
override val id = scala.util.Random.nextInt
}
val fred = new Student(1729)
fred.id
val james = new SecretAgent
james.id
7. 匿名子類
通過包含
帶有定義或重寫的
代碼塊的方法創建一個匿名的子類。匿名類作爲參數的定義類型爲:
Person{def greeting:String}
。
class Person(val name: String) {
override def toString = getClass.getName + "[name=" + name + "]"
}
val alien = new Person("Fred") {
def greeting = "Greetings, Earthling! My name is Fred."
}
def meet(p: Person{def greeting: String}) {
println(p.name + " says: " + p.greeting)
}
meet(alien)
8. 抽象類
abstract
關鍵字標記不能被實例化的類,因爲它的某個或幾個方法沒有被定義,這種沒有方法體的方法是抽象方法。某個類存在抽象方法,則必須申明爲
abstract
。有抽象方法以及下面將提到的抽象字段的存在才導致了抽象類的出現。子類中重寫超類的抽象方法時,不需要使用
override
關鍵字。
abstract class Person(val name: String) {
def id: Int // 沒有方法體的方法是 抽象方法
}
class Employee(name: String) extends Person(name) {
def id = name.hashCode // override 不需要
}
val fred = new Employee("Fred")
fred.id
9. 抽象字段
- 抽象字段:沒有初始值的字段。
abstract class Person {
val id: Int // 沒有初始化,帶有抽象getter方法的抽象字段
var name: String // 帶有抽象getter和setter方法
override def toString = getClass.getName + "[id=" + id + ",name=" + name + "]"
}
class Employee(val id: Int) extends Person { // 子類具體的id
var name = ""
}
val james = new Employee(7)
val fred = new Person {
val id = 1729
var name = "Fred"
}
10. 構造順序和提前定義
- 問題來源:子類將父類方法重寫後,父類構造時對應的方法失效,由子類來構造。如下例,實際構造完成後rannge的值爲2。
class Creature {
val range: Int = 10
val env: Array[Int] = new Array[Int](range)
}
class Ant extends Creature {
override val range = 2
}
有三種方法解決上述問題
將val申明爲final,安全但不靈活。
將val申明爲lazy,安全但不高效。
子類中使用提前定義。
提前定義:在超類構造之前初始化子類val字段,將val字段放在extends關鍵字之後的一個塊中,塊中不能包含類中其他字段。並且超類前用
with
關鍵字。
class Creature {
val range: Int = 10
val env: Array[Int] = new Array[Int](range)
}
class Ant extends Creature {
override val range = 2
}
class Bug extends {
override val range = 3
} with Creature
11. scala繼承層級
所有的Scala類都實現
ScalaObject
這個接口。Any
類是整個繼承層級的根節點。Null
唯一實例是null
值,可賦值給任何引用,但不能賦值給值類型變量。Unit
類型它的值是()
,可賦值給任何值變量。Nothing
類型沒有實例。
【待續】