### 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. 重寫字段
-
重寫有如下限制:
1. def只重寫另一個def。
1. val只能重寫另一個val或不帶參數的def。
1. 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
}
~~~
-
有三種方法解決上述問題
1.
將val申明為final,安全但不靈活。
1.
將val申明為lazy,安全但不高效。
1.
子類中使用提前定義。
-
提前定義:在超類構造之前初始化子類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`類型沒有實例。

【待續】