Skip to content

クラス

Kotlinは、クラスとオブジェクトによるオブジェクト指向プログラミングをサポートしています。オブジェクトは、プログラム内でデータを保存するのに便利です。 クラスを使用すると、オブジェクトの一連の特性を宣言できます。クラスからオブジェクトを作成することで、これらの特性を毎回宣言する必要がなくなるため、時間と手間を節約できます。

クラスを宣言するには、class キーワードを使用します:

kotlin
class Customer

プロパティ

クラスのオブジェクトの特性は、プロパティとして宣言できます。クラスのプロパティは以下の場所で宣言できます:

  • クラス名の後の丸括弧 () 内。
kotlin
class Contact(val id: Int, var email: String)
  • 波括弧 {} で囲まれたクラスボディ内。
kotlin
class Contact(val id: Int, var email: String) {
    val category: String = ""
}

クラスのインスタンスが作成された後に変更する必要がない限り、プロパティは読み取り専用 (val) として宣言することをお勧めします。

丸括弧内で valvar を付けずにプロパティを宣言することもできますが、その場合、インスタンス作成後にそれらのプロパティにアクセスすることはできません。

  • 丸括弧 () 内に含まれる内容は、クラスヘッダーと呼ばれます。
  • クラスプロパティを宣言する際、末尾のカンマ(trailing comma)を使用できます。

関数のパラメータと同様に、クラスのプロパティにもデフォルト値を設定できます:

kotlin
class Contact(val id: Int, var email: String = "[email protected]") {
    val category: String = "work"
}

インスタンスの作成

クラスからオブジェクトを作成するには、コンストラクタを使用してクラスのインスタンスを宣言します。

デフォルトでは、Kotlinはクラスヘッダーで宣言されたパラメータを持つコンストラクタを自動的に作成します。

例:

kotlin
class Contact(val id: Int, var email: String)

fun main() {
    val contact = Contact(1, "[email protected]")
}

この例では:

  • Contact はクラスです。
  • contactContact クラスのインスタンスです。
  • idemail はプロパティです。
  • デフォルトのコンストラクタで idemail を使用して contact を作成しています。

Kotlinのクラスは、自分で定義したものを含め、複数のコンストラクタを持つことができます。複数のコンストラクタを宣言する方法の詳細については、コンストラクタを参照してください。

プロパティへのアクセス

インスタンスのプロパティにアクセスするには、インスタンス名の後にピリオド . を付け、その後にプロパティ名を書きます:

kotlin
class Contact(val id: Int, var email: String)

fun main() {
    val contact = Contact(1, "[email protected]")
    
    // プロパティ email の値を出力
    println(contact.email)           
    // [email protected]

    // プロパティ email の値を更新
    contact.email = "[email protected]"
    
    // プロパティ email の新しい値を出力
    println(contact.email)           
    // [email protected]
}

文字列の一部としてプロパティの値を連結するには、文字列テンプレート(${})を使用できます。 例:

kotlin
println("Their email address is: ${contact.email}")

メンバ関数

オブジェクトの特性としてプロパティを宣言するだけでなく、メンバ関数でオブジェクトの振る舞いを定義することもできます。

Kotlinでは、メンバ関数はクラスボディ内で宣言する必要があります。インスタンスでメンバ関数を呼び出すには、インスタンス名の後にピリオド . を付け、その後に関数名を書きます。例:

kotlin
class Contact(val id: Int, var email: String) {
    fun printId() {
        println(id)
    }
}

fun main() {
    val contact = Contact(1, "[email protected]")
    // メンバ関数 printId() を呼び出す
    contact.printId()           
    // 1
}

データクラス

Kotlinには、データの保存に特に便利なデータクラス(data classes)があります。データクラスは通常のクラスと同じ機能を持ちますが、追加のメンバ関数が自動的に備わっています。これらのメンバ関数を使用すると、インスタンスを読みやすい形式で出力したり、クラスのインスタンス同士を比較したり、インスタンスをコピーしたりといったことが簡単にできます。これらの関数は自動的に利用可能になるため、各クラスごとに同じようなボイラープレートコード(定型的なコード)を書く手間が省けます。

データクラスを宣言するには、data キーワードを使用します:

kotlin
data class User(val name: String, val id: Int)

データクラスの最も便利な定義済みメンバ関数は以下の通りです:

関数説明
toString()クラスインスタンスとそのプロパティを読みやすい文字列で出力します。
equals() または ==クラスのインスタンス同士を比較します。
copy()別のインスタンスをコピーして新しいインスタンスを作成します。一部のプロパティのみを変更することも可能です。

各関数の使用例については、以下のセクションを参照してください:

文字列として出力

クラスインスタンスを読みやすい文字列で出力するには、toString() 関数を明示的に呼び出すか、println()print() 関数を使用します。これらの関数は内部で自動的に toString() を呼び出します。

kotlin
data class User(val name: String, val id: Int)

fun main() {
    val user = User("Alex", 1)
    
    // 出力が読みやすくなるよう、自動的に toString() 関数が使用されます
    println(user)            
    // User(name=Alex, id=1)
}

これは、デバッグやログの作成時に特に便利です。

インスタンスの比較

データクラスのインスタンスを比較するには、等価演算子 == を使用します:

kotlin
data class User(val name: String, val id: Int)

fun main() {
    val user = User("Alex", 1)
    val secondUser = User("Alex", 1)
    val thirdUser = User("Max", 2)

    // user と second user を比較
    println("user == secondUser: ${user == secondUser}") 
    // user == secondUser: true
    
    // user と third user を比較
    println("user == thirdUser: ${user == thirdUser}")   
    // user == thirdUser: false
}

インスタンスのコピー

データクラスのインスタンスの正確なコピーを作成するには、そのインスタンスで copy() 関数を呼び出します。

インスタンスのコピーを作成しつつ、一部のプロパティのみを変更したい場合は、copy() 関数を呼び出す際に関数パラメータとして変更したいプロパティの値を指定します。

例:

kotlin
data class User(val name: String, val id: Int)

fun main() {
    val user = User("Alex", 1)

    // user の正確なコピーを作成
    println(user.copy())       
    // User(name=Alex, id=1)

    // name を "Max" に変更した user のコピーを作成
    println(user.copy("Max"))  
    // User(name=Max, id=1)

    // id を 3 に変更した user のコピーを作成
    println(user.copy(id = 3)) 
    // User(name=Alex, id=3)
}

インスタンスのコピーを作成することは、元のインスタンスを直接変更するよりも安全です。なぜなら、元のインスタンスに依存している他のコードが、コピーやその後の操作による影響を受けないためです。

データクラスの詳細については、データクラスを参照してください。

このツアーの最後の章は、Kotlinの Null安全についてです。

練習問題

演習 1

2つのプロパティ(名前用のプロパティと給与用のプロパティ)を持つデータクラス Employee を定義してください。給与のプロパティは、年末に昇給できるように可変(mutable)にしてください。main 関数はこのデータクラスの使用例を示しています。

kotlin
// ここにコードを書いてください

fun main() {
    val emp = Employee("Mary", 20)
    println(emp)
    emp.salary += 10
    println(emp)
}
解答例
kotlin
data class Employee(val name: String, var salary: Int)

fun main() {
    val emp = Employee("Mary", 20)
    println(emp)
    emp.salary += 10
    println(emp)
}
演習 2

このコードをコンパイルするために必要な、追加のデータクラスを宣言してください。

kotlin
data class Person(val name: Name, val address: Address, val ownsAPet: Boolean = true)
// ここにコードを書いてください
// data class Name(...)

fun main() {
    val person = Person(
        Name("John", "Smith"),
        Address("123 Fake Street", City("Springfield", "US")),
        ownsAPet = false
    )
}
解答例
kotlin
data class Person(val name: Name, val address: Address, val ownsAPet: Boolean = true)
data class Name(val first: String, val last: String)
data class Address(val street: String, val city: City)
data class City(val name: String, val countryCode: String)

fun main() {
    val person = Person(
        Name("John", "Smith"),
        Address("123 Fake Street", City("Springfield", "US")),
        ownsAPet = false
    )
}
演習 3

コードをテストするために、ランダムな従業員を作成できるジェネレーターが必要です。候補となる名前の固定リスト(クラスボディ内)を持つ RandomEmployeeGenerator クラスを定義してください。最小給与と最大給与(クラスヘッダー内)でクラスを設定できるようにします。クラスボディ内に generateEmployee() 関数を定義してください。ここでも、main 関数はこのクラスの使用例を示しています。

TIP

この演習では、Random.nextInt() 関数を使用するためにパッケージをインポートしています。 パッケージのインポートの詳細については、パッケージとインポートを参照してください。

ヒント 1
リストには、リスト内のランダムなアイテムを返す .random() という拡張関数があります。
ヒント 2
Random.nextInt(from = ..., until = ...) は、指定された範囲内のランダムな Int 数値を返します。
kotlin
import kotlin.random.Random

data class Employee(val name: String, var salary: Int)

// ここにコードを書いてください

fun main() {
    val empGen = RandomEmployeeGenerator(10, 30)
    println(empGen.generateEmployee())
    println(empGen.generateEmployee())
    println(empGen.generateEmployee())
    empGen.minSalary = 50
    empGen.maxSalary = 100
    println(empGen.generateEmployee())
}
解答例
kotlin
import kotlin.random.Random

data class Employee(val name: String, var salary: Int)

class RandomEmployeeGenerator(var minSalary: Int, var maxSalary: Int) {
    val names = listOf("John", "Mary", "Ann", "Paul", "Jack", "Elizabeth")
    fun generateEmployee() =
        Employee(names.random(),
            Random.nextInt(from = minSalary, until = maxSalary))
}

fun main() {
    val empGen = RandomEmployeeGenerator(10, 30)
    println(empGen.generateEmployee())
    println(empGen.generateEmployee())
    println(empGen.generateEmployee())
    empGen.minSalary = 50
    empGen.maxSalary = 100
    println(empGen.generateEmployee())
}