データクラスとsealedクラス
値に基づく等価性とcopy()にはデータクラスを、網羅的な型階層と明確な状態モデルにはsealedクラスを使用します。
「データクラスとsealedクラス」はCoddyKit上の無料Android Academyレッスンです。 これはレッスン3/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはAndroid Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Android Academyコースには全4レッスンが含まれています。
データクラスとは
Kotlinのデータクラスは、主にデータを保持するためのクラスです。コンパイラーが便利なメソッドを自動生成します。
equals()— 2つのインスタンスを値で比較しますhashCode()— プロパティに基づく一貫したハッシュ値を生成しますtoString()— 読みやすい文字列表現を生成しますcopy()— 変更したコピーを作成します- 分解宣言をサポートします
データクラスの宣言
classの前にdataキーワードを追加します。すべてのプロパティはプライマリコンストラクターに記述する必要があります。
data class User(val id: Int, val name: String, val email: String)
fun main() {
val u1 = User(1, "Alice", "alice@example.com")
val u2 = User(1, "Alice", "alice@example.com")
println(u1) // User(id=1, name=Alice, email=alice@example.com)
println(u1 == u2) // true (value equality)
println(u1 === u2) // false (different objects)
}copy() — 1つのフィールドを変更する
copy()は、一部のプロパティを変更した新しいインスタンスを作成します。元のインスタンスは変更されません(不変性)。
data class Product(val name: String, val price: Double, val inStock: Boolean)
fun main() {
val original = Product("Laptop", 999.0, true)
// Only change the price; keep everything else
val onSale = original.copy(price = 799.0)
println(original) // Product(name=Laptop, price=999.0, inStock=true)
println(onSale) // Product(name=Laptop, price=799.0, inStock=true)
}分解宣言
データクラスは分解をサポートしています。コンパイラーが生成するcomponentN()関数を使って、プロパティを変数に展開できます。
data class Point(val x: Int, val y: Int)
fun main() {
val point = Point(10, 20)
// Destructure into separate variables
val (x, y) = point
println("x=$x, y=$y") // x=10, y=20
// Also works in for loops with maps
val scores = mapOf("Alice" to 95, "Bob" to 88)
for ((name, score) in scores) {
println("$name: $score")
}
}シールドクラスとは
シールドクラスは制限されたクラス階層です。すべてのサブクラスを同じファイル内に定義する必要があります。これにより、取り得る型の集合をコンパイル時に把握できます。
ネットワークの結果、UIの状態、ナビゲーションイベントなど、有限個の状態を表す場合にシールドクラスを使用します。
シールドクラスの構文
サブクラスは、クラスの内部または同じファイル内に直接宣言します。
sealed class NetworkResult<out T> {
data class Success<T>(val data: T) : NetworkResult<T>()
data class Error(val message: String, val code: Int = 0) : NetworkResult<Nothing>()
object Loading : NetworkResult<Nothing>()
}
fun handle(result: NetworkResult<String>) {
when (result) {
is NetworkResult.Success -> println("Data: ${result.data}")
is NetworkResult.Error -> println("Error ${result.code}: ${result.message}")
NetworkResult.Loading -> println("Loading...")
}
}シールドクラスとwhen(網羅性)
シールドクラスの強みは、whenが網羅的になることです。コンパイラーによって、すべてのサブタイプを処理するよう強制されるため、ケースの処理漏れを防げます。
sealed class UiState {
object Loading : UiState()
data class Success(val message: String) : UiState()
data class Error(val error: String) : UiState()
}
fun render(state: UiState): String = when (state) {
is UiState.Loading -> "Showing spinner"
is UiState.Success -> "Show: ${state.message}"
is UiState.Error -> "Error: ${state.error}"
// Compiler error if you remove any branch!
}
fun main() {
println(render(UiState.Loading))
println(render(UiState.Success("Loaded!")))
}シールドクラスとEnumの比較
どちらも固定された値の集合を表しますが、次の点が異なります。
- Enum — 各定数は単一のインスタンスで、バリアントごとの追加データを持ちません
- シールドクラス — 各バリアントが異なるデータを持つことができ、クラスまたはオブジェクトにできます
バリアントにデータが必要ない場合はEnumを使用します。バリアントごとに異なるプロパティが必要な場合はシールドクラスを使用します。
オブジェクト宣言(シングルトン)
objectはシングルトンを作成します。インスタンスは1つだけで、遅延生成され、スレッドセーフです。
object AppConfig {
const val BASE_URL = "https://api.example.com"
const val TIMEOUT = 30L
fun buildUrl(path: String) = "$BASE_URL/$path"
}
fun main() {
println(AppConfig.BASE_URL) // https://api.example.com
println(AppConfig.buildUrl("users")) // https://api.example.com/users
}コンパニオンオブジェクト
コンパニオンオブジェクトはクラスの内部に存在し、クラスレベルのメンバー(Javaのstaticに相当)を提供します。ファクトリメソッドによく使用されます。
class Token private constructor(val value: String) {
companion object {
fun create(raw: String): Token {
val cleaned = raw.trim()
require(cleaned.isNotEmpty()) { "Token must not be blank" }
return Token(cleaned)
}
}
}
fun main() {
val token = Token.create(" abc123 ")
println(token.value) // abc123
}実際のアプリで使うデータクラス
データクラスとシールドクラスを組み合わせると、状態をすっきりとモデル化できます。
data class Post(val id: Int, val title: String, val body: String)
sealed class PostState {
object Loading : PostState()
data class Loaded(val posts: List<Post>) : PostState()
data class Failed(val reason: String) : PostState()
}
fun showState(state: PostState) = when (state) {
PostState.Loading -> println("Fetching posts...")
is PostState.Loaded -> println("${state.posts.size} posts loaded")
is PostState.Failed -> println("Failed: ${state.reason}")
}
fun main() {
showState(PostState.Loaded(listOf(
Post(1, "Hello", "World"),
Post(2, "Kotlin", "Rocks")
)))
}確認問題
シールドクラスが通常の抽象クラスと異なる点を最もよく説明している文はどれですか。
まとめ:データクラスとシールドクラス
ここまでで、Kotlinの強力なツールを2つ学びました。
- data class — 値に基づく等価性、
copy()、分解、自動生成されるtoString() - sealed class — 有限の型階層、網羅的な
when、各バリアントが独自のデータを保持可能 - object — シングルトン、ファクトリメソッド用のコンパニオンオブジェクト
これらを組み合わせることで、Javaの定型コードを減らし、状態をすっきりと安全にモデル化できます。
よくある質問
「データクラスとsealedクラス」レッスンは無料ですか?
はい。「データクラスとsealedクラス」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Android Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Android Academyコースには全4レッスンが含まれています。
「データクラスとsealedクラス」で何を学びますか?
値に基づく等価性とcopy()にはデータクラスを、網羅的な型階層と明確な状態モデルにはsealedクラスを使用します。 ブラウザで直接実行するハンズオンコードでAndroid Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Android Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのAndroid Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン3/4です。
「データクラスとsealedクラス」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このAndroid Academyレッスンでコードを書いて実行できますか?
はい。すべてのAndroid Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- Null安全
- クラスとオブジェクト
- データクラスとsealedクラス
- 拡張関数と高階関数