woshidan's blog

あいとゆうきとITと、とっておきの話。

Kotlinでコンストラクタを書く

Kotlinで一からクラスを書く必要が出てきてかなり面食らったのでメモ。 KotlinのM11が一般的になる頃にまた追記しよう...。

参考: http://dev.classmethod.jp/smartphone/android-kotlin-introduction-04/ http://qiita.com/omochimetaru/items/98e015b0b694dd97f323

プライマリコンストラクタとセカンダリコンストラクタについて

これ、絶対Javaにもあるでしょう、と思っても私が師事しているGoogle先生は教えてくれなかったので、 たぶん、KotlinとかScalaとかC#とかのものでそんなにJavaのものではないのかもしれません。

Kotlinの場合、プライマリコンストラクタはクラス定義と一緒に定義されるコンストラクタであり、一見するとコンストラクタと思い難いため、初見ではかなり理解し難かったです。

プロパティの初期値やCompanion Objectの定義と初期化処理を設定することができます。

プライマリコンストラクタ以外のコンストラクタをセカンダリコンストラクタと言います。 セカンダリコンストラクタからはプライマリコンストラクタthis で呼び出すことが出来ます。

セカンダリコンストラクタは基本的にクラスブロックの中にあるので比較的コンストラクタっぽい見た目です。

プライマリコンストラクタを書く

参考: http://dev.classmethod.jp/smartphone/android-kotlin-introduction-04/

プライマリコンストラクタはクラス定義と同時に書きます。

public class Music(title:String) {
    val musicTitle = title
}

この、クラス定義のような顔をして書いてあるものがプライマリコンストラクタです。

このプライマリコンストラクタではval, varといったプロパティの定義やcompanion objectの定義、初期値の設定が出来ます。

public class Music(title:String) {
    val musicTitle = title

    companion object {
      fun create(): Music = Music()
    }
}

では、コンストラクタで初期化ついでにあれこれ処理を行いたい、といった場合はどう書くかというと、initブロックで書きます。

public class Music(title:String) {
    val musicTitle = title

    init {
      println("Music title ${title} is instantiated.")
    }

    companion object {
      fun create(): Music = Music()
    }
}

Javaでいうsuper()コンストラクタでどう書くかというと

public class Music extends Hobby {
  public Music(String title) {
     super()
     this.musicTitle = title
  }
}

の場合、以下のようになります。

public class Music(title:String) : Hobby() {
    val musicTitle = title
}

なるほどー。

セカンダリコンストラクタを書く

セカンダリコンストラクタconstructor()を使っていくつでも書けます。 プライマリコンストラクタと引数の数が揃っている必要もありません。

public class Music(title:String) : Hobby() {
    val musicTitle = title

    constructor(title: String, price: Int) {}
    constructor(title: String, category: String) {} 
}

セカンダリコンストラクタの中でプライマリコンストラクタを呼びたい場合、以下のようにthisを使います。

public class Music(title:String) {
  val musicTitle = title
   
  constructor(title: String, price: Int): this(title) {
  }
}

そういえば、関係ないのですが、あるコンストラクタから別のコンストラクタを呼ぶ処理が出てきて、あんまり触れたことがなかったので驚きました...。

コンストラクタでないsuperは使える

おまけになのですが、コンストラクタの継承というか、コンストラクタ周りの継承が特殊なだけで、それ以外のsuper()は普通に使えるみたいです。

// 申し訳程度の例
pubic class Hobby(title:String) {
  public fun play() {
     println("I'm plating ${title}")
  }
}

public class Music(title:String) : Hobby(title:String){
  val musicTitle = title
   
  constructor(title: String, price: Int): this(title) {
  }

  override public fun play() {
    println("♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪")
    super()
    println("♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪♪")
  }
}