面向對象:類和構造函數

Kotlin 做爲類 Java 語言,在面向對象上具備與 Java 類似的特性,可是針對不一樣的狀況進行了不一樣的優化,今天咱們簡單介紹一下 Kotlin 中的類和構造函數。java

1. 定義類和建立類的實例

Kotlin 中定義類與 Java 相同,使用 class 關鍵字:app

class 類名[主構造函數][{
  //類成員
}]

Kotlin 中的類名與 Java 相同,採用駱峯式命名法,首字母大寫。ide

不一樣的是,Kotlin 中的類若是是空類,沒有任何語句,則能夠省略大括號(閒的)。函數

要建立一個類的實例,只須要調用類的構造函數,不使用 new 關鍵字優化

val s = StringBuilder("Hello World")val list: List<String> = ArrayList()


2. 主構造函數

Kotlin 類的構造函數與 Java 有較大區別。首先,Kotlin 把構造函數分爲 主構造函數 和 次構造函數,主構造函數寫在類頭中,有且只有一個;次構造函數寫在類語句中,能夠有多個,也能夠沒有。ui

首先,咱們看一個簡單的 Java 類:this

public class Person {
    String name;
    public Person(String name) {
        this.name = name;
    }}

這個類定義一個 String 類型的成員變量 name,而後定義了帶有一個 String 類型參數的構造函數,這個構造函數把參數列表中的 name 賦給了成員變量 name。spa

用 Kotlin,咱們能夠這樣寫:orm

class Person constructor(name: String) {
    val name: String
    init {
        this.name = name
    }}

首先,咱們使用 class 定義了一個類 Person,而後在類頭用 constructor 關鍵字定義帶有一個 String 類型參數的主構造函數。在類體裏,咱們定義了一個不可變的 String 類型成員變量 name,而後使用 init 關鍵字定義主構造函數的行爲,把主構造函數的 name 參數賦給成員變量 name。對象

能看到,Kotlin 類的主構造函數,參數列表定義在類聲明的部分,函數體卻在 init 代碼塊裏。(莫名其妙)

這樣寫不夠簡潔呀!實際上,充分利用 Kotlin 提供的特性,咱們能夠把這個類縮短到一行:

class Person(val name: String)

看吧,全部冗餘信息都已除去,只保留了最關鍵的部分。想理解這句話,咱們須要知道主構造函數定義中的兩個細節:

  1. 若是主構造函數沒有任何修飾符,則能夠去掉 constructor 關鍵字。這樣,咱們的類定義就很像一個函數了:

    class Person(name: String) {/*……*/}

    若是想使用在主構造函數前使用修飾符,那麼這個 constructor 就不能省了:

    class Person private constructor() {/*……*/}
  2. 若是主構造函數中定義的參數使用 val 或者 var 修飾,則會建立與這個參數同名的成員變量,並使用傳入的參數值初始化這個成員變量。簡單來講,就是把「定義成員變量」和「使用構造函數傳入的參數初始化成員變量」簡化爲一個 val 或者 var 關鍵字。

    上面的例子中,咱們在主構造方法裏聲明 val name: String,Kotlin 就會自動爲咱們添加一個名爲 name 的不可變的 String 類型成員變量,而後用主構造函數傳入的值初始化這個成員變量,能夠直接調用。

3. 次構造函數

Java 中,一個類每每有多個不一樣的構造函數,它們通常有下面兩種關係:

  1. 參數列表由少到多,參數列表少的構造函數使用 默認值 調用參數列表多的構造函數。對於這個常見的類型,Kotlin 中使用 函數默認參數 的方法簡化代碼;

  2. 不一樣的構造方法使用不一樣的參數列表,相互之間存在調用關係。Kotlin 中使用 次構造函數委託 的解決方法。

首先看第一種狀況,這裏咱們給用 Java 寫的 Person 類添加一些東西:

public class Person {
  long id;
  String name = "";
  int age = 0;

  public Person(long id, String name, int age) {
    this.id = id;
    this.name = name;
    this.age = age;
  }
  public Person(long id, String name) {
    this.id = id;
    this.name = name;
  }
  public Person(long id, int age) {
    this.id = id;
    this.age = age;
  }
  public Person(long id) {
    this.id = id;
  }}

咱們添加了兩個屬性,一個 long 類型的 id,一個 int 類型的 age。三個構造函數都須要傳入 id 變量,name 和 age 變量的要求則是 若是沒有外部傳入的參數,就使用默認值

使用 Kotlin,咱們能夠大大簡化這一長串代碼:

class Person(val id: Long, val name: String = "", val age: Int = 0)

好吧,Kotlin 又是隻用一行就解決了問題……

咱們重點看一下參數列表:

  • 參數列表中定義了三個參數,都使用 val 關鍵字修飾,說明要使用它們建立成員變量並初始化;

  • name 和 age 參數後面都使用 = 默認值 的方法聲明瞭它們的默認值,在調用主構造函數的時候,若是不傳入參數,就使用指定的默認值。

對於構造函數的第二種類型:使用沒有關係的參數列表,但存在調用關係,Kotlin 中的處理方式是使用次構造函數委託主構造函數。咱們接着改一下 Person 類:

public class Person {
  long id;
  String name = "";

  public Person(long id) {
    this.id = id;
  }
  public Person(String name) {
    this(name.hashCode());
    this.name = name;
  }}

使用 Kotlin,咱們能夠這樣寫:

class Person(val id: Long) {
  var name: String = ""

  constructor(name: String) : this(name.hashCode().toLong()) {
    this.name = name
  }}

首先,咱們在主構造函數裏聲明瞭並初始化了成員變量 id,而後在類體內使用 constructor 關鍵字定義一個帶有一個 String 類型參數的 次構造方法,這個次構造方法先調用主構造函數,而後將參數賦給成員變量。這裏有幾個須要注意的地方:

  1. 若是類已經有了一個主構造函數,那麼全部的次構造函數都要直接或間接地委託給主構造函數。也能夠先委託給其餘的次構造函數,再由它們委託給主構造函數。全部的次構造函數都會先調用主構造函數,再執行本身特有的代碼。寫法:

    constructor([參數列表]): this([參數列表]) {/*……*/}
  2. 次構造函數不能在參數列表中聲明並初始化成員變量,這也是上面「name: String」前面爲何沒有 val 的緣由。並且由於次構造函數會改動 name 的值,因此 name 必須聲明爲 var。

相關文章
相關標籤/搜索