Kotlin學習筆記(5)- 類
系列文章全部為本人的學習筆記,若有任何不妥之處,隨時歡迎拍磚指正。如果你覺得我的文章對你有用,歡迎關注我,我們一起學習進步!
Kotlin學習筆記(1)- 環境配置
Kotlin學習筆記(2)- 空安全
Kotlin學習筆記(3)- 語法
Kotlin學習筆記(4)- 流程控制
Kotlin學習筆記(5)- 類
Kotlin學習筆記(6)- 屬性
Kotlin學習筆記(7)- 介面
Kotlin學習筆記(8)- 擴充套件
Kotlin學習筆記(8)- 擴充套件(續)
Kotlin學習筆記(9)- 資料類
Kotlin學習筆記(10)- 泛型
Kotlin學習筆記(11)- 內部類和巢狀類
Kotlin學習筆記(12)- 委託
Kotlin學習筆記(13)- 函數語言程式設計
Kotlin學習筆記(14)- lambda
一、類
1.類修飾符
修飾符分為屬性修飾符和訪問許可權修飾符。
// 屬性修飾符
annotation //註解類
abstract //抽象類
final //類不可繼承,預設屬性
enum //列舉類
open //類可繼承,類預設是final的
// 訪問許可權修飾符
private //僅在同一個檔案中可見
protected //同一個檔案中或子類可見
public //所有呼叫的地方都可見
internal //同一個模組中可見
2.類定義
kotlin預設唯一構造器,暨類定義同時也是構造器。
class Person(name : String, age : int) {
}
翻譯成java為:
final public class Person {
public Person(String name, int age){
}
}
3.建構函式
仔細看會發現,翻譯成的java類定義前面有final
修飾符,因為在kotlin中類預設為final
的,也就是不可繼承的。如果要繼承,需要宣告為open
,或者abstract
。
class Person(name : String, age : int)
如果連引數也沒有,也可以這麼寫
class Person
4.類初始化
因為kotlin中的類定義同時也是建構函式,這個時候是不能進行操作的,所以kotlin增加了一個新的關鍵字init
用來處理類的初始化問題,init模組中的內容可以直接使用建構函式的引數。
class Person(name : String, age : int){
init{
// to do something
}
}
5.次級建構函式
我們知道,java中可以有多個不同型別、不同個數的同名建構函式,以此滿足我們的各種需求。而上面我們說過,kotlin中的類定義同時也是建構函式,kotlin中也預設只有這一個建構函式,那我們怎麼辦呢?很常見的一個問題是,View
的自定義。根據android系統版本不同,View
有3到4個建構函式,如果只用kotlin中的預設建構函式,我們確實可以在普通程式碼中正常使用,那麼如何在xml
中進行定義呢?舊版的kotlin沒有處理這個問題,我們只能在java中自定義View
,然後再進行呼叫。而在新版的kotlin已經解決了這個問題,那就是次級建構函式constructor。
次級建構函式用constructor
加上引數,後面用this
加上主建構函式的引數。同時次級建構函式中可以直接進行程式碼操作,所以沒有init
模組
class ParentClass(name: String) {
var a = 1
init {
log("This is --> primary constructor, a=$a, name=$name")
}
constructor(name : String, age : Int) : this(name) {
log("This is --> secondry constructor, a=${++a}, age=$age")
}
}
// 翻譯成java
final class ParentClass{
int a = 1;
public ParentClass(String name){
log("This is --> primary constructor, a=$a, name=$name")
}
public ParentClass(String name, int age){
this(name);
log("This is --> secondry constructor, a=${++a}, age=$age")
}
}
// 也就是說,如果新建一個類ParentClass("name", age),那麼就會進行兩次log輸出
6.引數預設值
kotlin中支援類定義的時候,引數可以設定預設值。
// 含有預設值的引數,可以不傳,也就是說ParentClass("xiaoming", 22, 1)和ParentClass("xiaoming", 22)這兩種呼叫方式都是可以的
constructor(name : String, age : Int, sex : Int = 0) : this(name) {
log("This is --> secondry constructor, a=${++a}, age=$age, sex=$sex")
}
如果建構函式中的所有引數都有預設值,則kotlin會多建立一個無引數的建構函式。
constructor(name : String = "", age : Int = 12, sex : Int = 0) : this(name) {
log("This is --> secondry constructor, a=${++a}, age=$age, sex=$sex")
}
如果有多個建構函式,且某個或某幾個建構函式中有預設值,則kotlin會選擇最符合條件的一個作為建構函式。在下面的示例中,第三個建構函式的第三個引數是有預設值的,可以不傳,這就和第二個建構函式有了相同的假象。kotlin的規則是,選擇最符合條件的一個,也就是如果你這樣建立:ParentClass("xiaoming", 22)
,kotlin會先去找只有這兩引數型別的建構函式,也就是第二種。
class ParentClass(name: String) {
var a = 1
init {
log("This is --> primary constructor, a=$a, name=$name")
}
constructor(name : String, age : Int) : this(name) {
log("This is --> secondry constructor, a=${++a}, age=$age")
}
constructor(name : String, age : Int, sex : Int = 0) : this(name) {
log("This is --> secondry constructor, a=${++a}, age=$age, sex=$sex")
}
}
二、繼承
1.繼承的基本使用
在kotlin中,類預設是final
型別的,也就是不可繼承的。如果需要繼承,需要顯式的將類宣告為open
。我覺得這其實也表現出kotlin不推薦使用繼承的一種態度,畢竟在物件導向設計中,是推薦多用組合、少用繼承的。kotlin使用冒號:
代替java中的extend
來表示繼承關係,如果父類的建構函式有引數,則在繼承時也要註明。
open class ParentClass(name: String) {
var a = 1
init {
log("This is --> primary constructor, a=$a, name=$name")
}
}
class Child(name: String, age : Int) : ParentClass(name){
}
2.多建構函式的繼承
次級建構函式初始化使用super
關鍵字,類似於java中的super
class Child2 : ParentClass {
constructor(name : String) : super(name){
log("Child2 age : $name")
}
// 可以對引數進行擴充套件
constructor(name: String, age: Int) : super(name){
}
}
3.方法過載
同樣的,秉承著多用組合、少用繼承的原則,類中的方法預設也是final
的,父類如果想要某個方法可以被子類過載,那麼這個方法也要顯式的被宣告為open
;而子類如果要過載父類的方法,則該方法必須使用override
關鍵字。
open class ParentClass(name: String) {
open fun publicMethod(){
log("I am public")
}
}
class Child(name: String, age : Int) : ParentClass(name){
override fun publicMethod() {
super.publicMethod()
}
}
成員標記為override
的本身是開放的,也就是說,它可以在子類中重寫。如果你想禁止重寫的,使用final
關鍵字。
class Child(name: String, age : Int) : ParentClass(name){
final override fun publicMethod() {
super.publicMethod()
}
}
4.同名方法
我們可能還會遇到一種問題:類實現了多個介面,其中某些介面中恰好有相同的方法。kotlin中使用尖括號對父類進行標記,以示區分。
open class ParentClass(name: String) {
open fun publicMethod(){
log("I am public from ParentClass")
}
}
interface ParentInterface(name: String) {
fun publicMethod(){
log("I am public from ParentInterface")
}
}
class Child(name: String, age : Int) : ParentClass(name),ParentInterface{
override fun publicMethod() {
super<ParentClass>.publicMethod()
super<ParentInterface>.publicMethod()
}
}
三、抽象
和java一樣,抽象也使用abstract
關鍵字。抽象類中可以沒有抽象方法,但抽象方法一定在抽象類中。那麼既然是抽象的,那麼肯定是需要繼承的,所以abstract
自動包含open
屬性,這也是不言而喻的。
abstract class ParentClass(name: String) {
abstract fun abstractMethod()
}
class Child(name: String, age : Int) : ParentClass(name){
override fun abstractMethod() {
//To implemented it
}
}
其實抽象用到的也是繼承,但是為什麼沒有放到第二部分裡呢?這裡有一點個人的理解。我覺得抽象和單純的繼承在使用目的上是有本質區別的。抽象是為了封裝變化,將不同的實現交給不同的子類去完成。而單純的繼承和方法過載反而破壞了封裝的美感,既然需要通過過載父類方法來實現目的,那很可能你在設計父類的時候就已經做出了不恰當的決定。
相關文章
- Kotlin學習筆記-類和介面Kotlin筆記
- Kotlin學習筆記 其他Kotlin筆記
- Kotlin for Java Developers 學習筆記KotlinJavaDeveloper筆記
- Kotlin 入門學習筆記Kotlin筆記
- Web 開發學習筆記(5) — 抽象出 Page 類Web筆記抽象
- Kotlin學習筆記-基礎語法Kotlin筆記
- Vue學習筆記5Vue筆記
- git學習筆記5Git筆記
- CCNA學習筆記5筆記
- TS學習筆記(三):類筆記
- 強化學習-學習筆記5 | AlphaGo強化學習筆記Go
- HTML5學習筆記HTML筆記
- Android學習筆記(5)Android筆記
- PL/SQL學習筆記-5SQL筆記
- ruby字串學習筆記5字串筆記
- [學習筆記 #5] 雜湊筆記
- 抽象類特點 學習筆記抽象筆記
- java學習筆記(包裝類)Java筆記
- 類的基礎學習筆記筆記
- Kotlin學習筆記(五十八)正規表示式Kotlin筆記
- G01學習筆記-5筆記
- swift學習筆記《5》- 實用Swift筆記
- H5學習筆記(一)H5筆記
- MD5之學習筆記筆記
- railscasts學習筆記(5-2)AIAST筆記
- HTML5學習筆記 拖放HTML筆記
- spring-5學習筆記Spring筆記
- 類歐幾里得演算法學習筆記演算法筆記
- TypeScript學習筆記之五類(Class)TypeScript筆記
- iOS學習筆記43 Swift(三)類iOS筆記Swift
- Java學習筆記之類和物件Java筆記物件
- OpenCV學習筆記(5)——normalize函式OpenCV筆記ORM函式
- Flutter學習筆記(5)--Dart運算子Flutter筆記Dart
- linux學習筆記-day5Linux筆記
- 比特幣學習筆記——————5、 交易比特幣筆記
- Linux學習筆記 Day 4~5Linux筆記
- 兒童教育講座 - 學習筆記 5筆記
- 第5輪學習筆記規劃筆記