scala_繼承、型別判斷、抽象類、匿名內部類
繼承
scala語言是支援物件導向程式設計的,我們也可以使用scala來實現繼承,通過繼承來減少重複程式碼。
定義語法
- scala和Java一樣,使用extends關鍵字來實現繼承
- 可以在子類中定義父類中沒有的欄位和方法,或者重寫父類的方法
- 類和單例物件都可以從某個父類繼承
語法
class/object 子類 extends 父類 {
..
}
示例 | 類繼承
- 定義一個Person類,再定義一個Student類,繼承自Person類
-
建立一個Student類物件例項,並設定name為“張三”
-
列印姓名
參考程式碼
class Person {
var name = "super"
def getName = this.name
}
class Student extends Person
object Main13 {
def main(args: Array[String]): Unit = {
val p1 = new Person()
val p2 = new Student()
p2.name = "張三"
println(p2.getName)
}
}
示例 | 單例物件繼承
示例說明
- 建立一個Student單例物件,讓單例物件繼承示例1中的Person類
- 設定單例物件的名字為"張三",呼叫Student單例物件的getName方法
class Person {
var name = "super"
def getName = this.name
}
object Student extends Person
object Main13 {
def main(args: Array[String]): Unit = {
println(Student.getName)
}
}
override和super
類似於Java語言,我們在子類中使用override需要來重寫父類的成員,可以使用super來引用父類
用法
- 子類要覆蓋父類中的一個方法,必須要使用override關鍵字
- 使用override來重寫一個val欄位
- 使用super關鍵字來訪問父類的成員方法
示例
示例說明
- 定義一個Person類,包含
- 姓名欄位(不可重新賦值)
- 獲取姓名方法
- 定義一個Student類
- 重寫姓名欄位
- 重寫獲取姓名方法,返回"hello, " + 姓名
- 建立Student物件示例,呼叫它的getName方法
參考程式碼
class Person {
val name = "super"
def getName = name
}
class Student extends Person {
// 重寫val欄位
override val name: String = "child"
// 重寫getName方法
override def getName: String = "hello, " + super.getName
}
object Main13 {
def main(args: Array[String]): Unit = {
println(new Student().getName)
}
}
型別判斷
有時候,我們設計的程式,要根據變數的型別來執行對應的邏輯。
在scala中,如何來進行型別判斷呢?
有兩種方式:
- isInstanceOf
- getClass/classOf
isInstanceOf/asInstanceOf
在Java中,我們可以使用instanceof關鍵字來判斷型別、以及(型別)object來進行型別轉換,在scala中如何實現呢?
scala中物件提供isInstanceOf和asInstanceOf方法。
- isInstanceOf判斷物件是否為指定類的物件
- asInstanceOf將物件轉換為指定型別
用法
// 判斷物件是否為指定型別
val trueOrFalse:Boolean = 物件.isInstanceOf[型別]
// 將物件轉換為指定型別
val 變數 = 物件.asInstanceOf[型別]
示例
示例說明
- 定義一個Person類
- 定義一個Student類繼承自Person類
- 建立一個Student類物件
- 判斷該物件是否為Student型別,如果是,將其轉換為Student型別並列印該物件
參考程式碼
class Person3
class Student3 extends Person3
object Main3 {
def main(args: Array[String]): Unit = {
val s1:Person3 = new Student3
// 判斷s1是否為Student3型別
if(s1.isInstanceOf[Student3]) {
// 將s1轉換為Student3型別
val s2 = s1.asInstanceOf[Student3]
println(s2)
}
}
}
getClass和classOf
isInstanceOf 只能判斷物件是否為指定類以及其子類的物件,而不能精確的判斷出,物件就是指定類的物件。如果要求精確地判斷出物件就是指定類的物件,那麼就只能使用 getClass 和 classOf 。
用法
- p.getClass可以精確獲取物件的型別
- classOf[x]可以精確獲取型別
- 使用==操作符可以直接比較型別
示例
示例說明
- 定義一個Person類
- 定義一個Student類繼承自Person類
- 建立一個Student類物件,並指定它的型別為Person型別
- 測試使用isInstance判斷該物件是否為Person型別
- 測試使用getClass/classOf判斷該物件是否為Person型別
- 測試使用getClass/classOf判斷該物件是否為Student型別
參考程式碼
class Person4
class Student4 extends Person4
object Student4{
def main(args: Array[String]) {
val p:Person4=new Student4
//判斷p是否為Person4類的例項
println(p.isInstanceOf[Person4])//true
//判斷p的型別是否為Person4類
println(p.getClass == classOf[Person4])//false
//判斷p的型別是否為Student4類
println(p.getClass == classOf[Student4])//true
}
}
抽象類
和Java語言一樣,scala中也可以定義抽象類
定義
如果類的某個成員在當前類中的定義是不包含完整的,它就是一個抽象類
不完整定義有兩種情況:
- 方法沒有方法體(抽象方法)
- 變數沒有初始化(抽象欄位)
定義抽象類和Java一樣,在類前面加上abstract關鍵字
// 定義抽象類
abstract class 抽象類名 {
// 定義抽象欄位
val 抽象欄位名:型別
// 定義抽象方法
def 方法名(引數:引數型別,引數:引數型別...):返回型別
}
抽象方法
示例
- 設計4個類,表示上述圖中的繼承關係
- 每一個形狀都有自己求面積的方法,但是不同的形狀計算面積的方法不同
步驟
- 建立一個Shape抽象類,新增一個area抽象方法,用於計算面積
- 建立一個Square正方形類,繼承自Shape,它有一個邊長的主構造器,並實現計算面積方法
- 建立一個長方形類,繼承自Shape,它有一個長、寬的主構造器,實現計算面積方法
- 建立一個圓形類,繼承自Shape,它有一個半徑的主構造器,並實現計算面積方法
- 編寫main方法,分別建立正方形、長方形、圓形物件,並列印它們的面積
參考程式碼
// 建立形狀抽象類
abstract class Shape {
def area:Double
}
// 建立正方形類
class Square(var edge:Double /*邊長*/) extends Shape {
// 實現父類計算面積的方法
override def area: Double = edge * edge
}
// 建立長方形類
class Rectangle(var length:Double /*長*/, var width:Double /*寬*/) extends Shape {
override def area: Double = length * width
}
// 建立圓形類
class Cirle(var radius:Double /*半徑*/) extends Shape {
override def area: Double = Math.PI * radius * radius
}
object Main6 {
def main(args: Array[String]): Unit = {
val s1:Shape = new Square(2)
val s2:Shape = new Rectangle(2,3)
val s3:Shape = new Cirle(2)
println(s1.area)
println(s2.area)
println(s3.area)
}
}
抽象欄位
在scala中,也可以定義抽象的欄位。如果一個成員變數是沒有初始化,我們就認為它是抽象的。
定義
語法
abstract class 抽象類 {
val/var 抽象欄位:型別
}
示例
示例說明
- 建立一個Person抽象類,它有一個String抽象欄位WHO_AM_I
- 建立一個Student類,繼承自Person類,重寫WHO_AM_I欄位,初始化為學生
- 建立一個Policeman類,繼承自Person類,重寫WHO_AM_I欄位,初始化警察
- 新增main方法,分別建立Student/Policeman的例項,然後分別列印WHO_AM_I
參考程式碼
// 定義一個人的抽象類
abstract class Person6 {
// 沒有初始化的val欄位就是抽象欄位
val WHO_AM_I:String
}
class Student6 extends Person6 {
override val WHO_AM_I: String = "學生"
}
class Policeman6 extends Person6 {
override val WHO_AM_I: String = "警察"
}
object Main6 {
def main(args: Array[String]): Unit = {
val p1 = new Student6
val p2 = new Policeman6
println(p1.WHO_AM_I)
println(p2.WHO_AM_I)
}
}
匿名內部類
匿名內部類是沒有名稱的子類,直接用來建立例項物件。Spark的原始碼中有大量使用到匿名內部類。
scala中的匿名內部類使用與Java一致。
定義
語法
val/var 變數名 = new 類/抽象類 {
// 重寫方法
}
示例
示例說明
- 建立一個Person抽象類,並新增一個sayHello抽象方法
- 新增main方法,通過建立匿名內部類的方式來實現Person
- 呼叫匿名內部類物件的sayHello方法
參考程式碼
abstract class Person7 {
def sayHello:Unit
}
object Main7 {
def main(args: Array[String]): Unit = {
// 直接用new來建立一個匿名內部類物件
val p1 = new Person7 {
override def sayHello: Unit = println("我是一個匿名內部類")
}
p1.sayHello
}
}
相關文章
- 繼承+多型+抽象類繼承多型抽象
- 匿名內部類泛型泛型
- c#中判斷類是否繼承於泛型基類C#繼承泛型
- PHP 抽象類繼承抽象類時的注意點PHP 抽象類繼承抽象類時的注意點PHP抽象繼承
- 匿名內部類
- PHP 抽象類繼承抽象類時的注意點PHP抽象繼承
- Java內部類詳解--匿名內部類Java
- java內部類,區域性內部類,靜態內部類,匿名內部類Java
- java內部類之成員內部類之匿名內部類Java
- Java類與匿名內部類Java
- Java之繼承和抽象類Java繼承抽象
- JAVA介面繼承、抽象類等Java繼承抽象
- 繼承 重寫和抽象類繼承抽象
- 匿名內部類理解
- 如何判斷一個類是從另一個類繼承繼承
- Java內部類和匿名內部類的用法Java
- 10-Java內部類——成員內部類、區域性內部類、匿名內部類Java
- c# abstract抽象類及抽象方法_繼承C#抽象繼承
- java之內部類(InnerClass)----非靜態內部類、靜態內部類、區域性內部類、匿名內部類Java
- Java基礎10---包、內部類、匿名內部類Java
- 類的繼承_子類繼承父類繼承
- C# OOP:繼承,介面和抽象類C#OOP繼承抽象
- java培訓教程:什麼是匿名內部類?怎樣建立匿名內部類?Java
- Java 的抽象類, 介面以及內部類Java抽象
- Java基礎之介面與抽象類及多型、內部類Java抽象多型
- Java中的匿名內部類及內部類的二三事Java
- 介面是否可繼承(extends)介面? 抽象類是否可實現 (implements)介面? 抽象類是否可繼承具體類(concrete class)?繼承抽象
- Java的特殊類用法:檔案類、內部類、本地類、匿名類Java
- TypeScript(5)類、繼承、多型TypeScript繼承多型
- 6-2 抽象類的繼承 (5分)抽象繼承
- 深入理解java巢狀類和內部類、匿名類Java巢狀
- java匿名內部類:“ 儂好,世界”Java
- Java抽象類、繼承及多型和介面卡的實現Java抽象繼承多型
- JS資料型別分類和判斷JS資料型別
- c# abstract抽象類與繼承類子類的建構函式_baseC#抽象繼承函式
- Java基礎10 介面的繼承與抽象類Java繼承抽象
- 3.6 Java內部類四種型別Java型別
- 泛型,內部類泛型