classにつけられるキーワード

classにつけられるキーワード

  • data - 値型もどき
  • sealed - 代数的データ型もどき
  • inner - Outerクラスの呼び出しが可能となる
  • enum - Javaenum
  • open - Javafinalの反対。Kotlinの全てのclassはデフォルトでfinalであるため
  • value - ?

data class

自動導出されるメソッド

プライマリコンストラクタを用いて、以下のメソッドが自動導出される。

  • equals() / hashCode() ペア - 同値比較
  • toString() - 値の文字列化
  • copy() - 値のコピー
  • componentN() - 値の分割代入

equals() / hashCode()

data classは同値比較。値が同じかどうか。

data class UserData(var name: String)

val tanaka = UserData("tanaka")
val tanaka2 = UserData("tanaka")
println(tanaka == tanaka2) // true

classは、デフォルトでは、同一比較。インスタンスが同じかどうか。

class User(var name: String)

val tanaka = User("tanaka")
val tanaka2 = User("tanaka")
println(tanaka == tanaka2) // false

toString()

data classの場合

data class UserData(var name: String)

println(UserData("tanaka")) // UserData(name=tanaka)

classの場合

class User(var name: String)

println(User("tanaka")) // Classes.User@4ca8195f

copy()

data classの代入はそのまま参照コピーされる

data class UserData(var name: String)

val tanaka = UserData("tanaka)
val tanaka2 = tanaka

// true
println(System.identityHashCode(tanaka) == System.identityHashCode(tanaka2)) 

tanaka2.name = "yoshida"
println(tanaka.name) // yoshida

copy()インスタンスを複製する。

data class UserData(var name: String)

val tanaka = UserData("tanaka)
val tanaka2 = tanaka.copy()

tanaka2.name = "yoshida"
println(tanaka.name) // tanaka

componentN()

分割代入

プライマリーコンストラクタのプロパティ数に応じて、compoennt1(), ...を自動導出する。

data class UserData(val name: String, val age: Int)
val tanaka = UserData("tanaka", 27)

// 分割代入
val (name, age) = tanaka
println("name: ${name}, age: $age")

通常classとの違い

プライマリコンストラクタは、最低限一つのプロパティを持つ必要がある。

// コンパイルエラー
// Data class must have at least one primary constructor parameter
data class User() 

プライマリコンストラクタのプロパティは、var もしくは varである必要がある。

// コンパイルエラー
// Data class primary constructor must have only property (val / var) parameters
data class User(name: String) { 
    val last_name = name
}

abstract, oepn, sealed, innerをつけることができな

// コンパイルエラー
// Modifier 'data' is incompatible with 'open
open data class User(val name: String) {}

sealed

代数的データ型の作成。

sealed class Barcode {
    // dataキーワードを付けることが出来る
    data class UPC(val p1: Int, val p2: Int, val p3: Int, val p4: Int): Barcode()
    class QRCode(a: String): Barcode()
}

var productBarcode = Barcode.UPC(8, 85909, 51226, 3)
println(productBarcode)

内部に記述しなくても良い

sealed class Barcode()
data class UPC(val p1: Int, val p2: Int, val p3: Int, val p4: Int): Barcode()
class QRCode(a: String): Barcode()

// 名前空間が取れる
var productBarcode = UPC(8, 85909, 51226, 3)
println(productBarcode)

whenによるdestructingが対応されていないのでパターンマッチングが微妙ではある。

// 型アノテーションを付ける必要がある
//val barcode: Barcode = Barcode.UPC(8, 85909, 51226, 3)
val barcode: Barcode = Barcode.QRCode("http://yossan.github.io")
// 型におけるパターンマッチングが可能
when(barcode) {
    is Barcode.UPC -> {
        if (barcode is Barcode.UPC) { // smart case 
            val (p1, p2, p3, p4) = barcode
            println("UPC($p1, $p2, $p3, $p4)")
        }
    }
    is Barcode.QRCode -> {
        if (barcode is Barcode.QRCode) { // smart case 
            val (p) = barcode
            println("QRCode($p)")
        }
    }
}

sealedは、interfaceにもつけることも可能

sealed interface Expr

inner

https://kotlinlang.org/docs/nested-classes.html

nested classは、外側のclassに基本アクセスできない

class Outer {
    private val bar: Int = 1
    class Inner {
        // Unresolved reference: bar
        fun foo() = bar
    }
}

innerキーワードを付けることでアクセスが可能となる。

class Outer {
    private val bar: Int = 1
    inner class Inner {
        fun foo() = bar
    }
}

val demo = Outer().Inner().foo()

Annonymouse inner class

object式を使ったインスタンス生成は、Annonyous inner class instanceとなる。

→ 内部でOuterクラスの変数が使える。

window.addMouseListener(object : MouseAdapter() {

    override fun mouseClicked(e: MouseEvent) { ... }

    override fun mouseEntered(e: MouseEvent) { ... }
})

// This type is final, so it cannot be inherited from // class MyApp: App()

enum

https://kotlinlang.org/docs/enum-classes.html

それぞれのenum定数はobjectになる。

value

https://kotlinlang.org/docs/inline-classes.html