Step1-3:【基礎編】Kotlin言語のキホンをマスターしよう!
TKPLのアウトライン
- ステップ1:【基礎編】Kotlin言語のキホンをマスターしよう!
サブトピック1-1:プログラミングの第一歩
サブトピック1-2:プログラムの流れを操る
サブトピック1-3:オブジェクト指向って何?←今回はここ
- ステップ2:【入門編】はじめてのAndroidアプリ開発
サブトピック2-1:開発環境の準備と初めてのアプリ
サブトピック2-2:アプリの画面を作ってみよう
サブトピック2-3:効率的なリスト表示
- ステップ3:【実践編】機能的なアプリを作るための応用技術
サブトピック3-1:データを保存する (Data Persistence)
サブトピック3-2:インターネットと通信する (Networking & Concurrency)
サブトピック3-3:画面遷移とアーキテクチャ (Navigation & Architecture)
Kotlin基礎解説:第3回 クラスとオブジェクト指向
これまでの記事でKotlinの変数や制御構文について見てきました。今回は、プログラムの設計における中核的な概念であるオブジェクト指向、特にその基本単位となるクラスの定義に焦点を当てます。
1. クラスの定義
まず、nameとlevelというプロパティを持つPlayerクラスを例に、JavaとKotlinの記述量を比較します。
※nameはval(不変)、levelはvar(可変)で定義してみます。
Javaの場合
フィールド、コンストラクタ、getter/setterをそれぞれ記述する必要があります。
※JavaでもLombokライブラリを使って"@Data"アノテーションを付与すれば、getter/setterメソッドやequalsメソッドを書く必要がなくなります
public class Player {
private final String name;
private int level;
public Player(String name, int level) {
this.name = name;
this.level = level;
}
public String getName() {
return name;
}
public int getLevel() {
return level;
}
public void setLevel(int level) {
this.level = level;
}
}
Kotlinの場合
Kotlinでは、このクラスをわずか1行で定義できます。
class Player(val name: String, var level: Int)
とてつもなく簡潔になりましたね笑
クラス定義時のこの簡潔さは、Kotlinのプライマリコンストラクタとプロパティという2つの強力な機能によって実現されています。
2. Kotlinクラスの構成要素
2.1 プライマリコンストラクタとプロパティ
Kotlinでは、クラス名の直後に続く(…)の部分をプライマリコンストラクタと呼びます。ここにvalまたはvarを付けて引数を宣言するだけで、Kotlinはそれをクラスのプロパティとして扱います。
プライマリコンストラクタという機能が自動的に処理してくれること
- Javaでいうフィールドの宣言
- コンストラクタ引数からフィールドへの値の代入
- valに対するgetterの自動生成
- varに対するgetterおよびsetterの自動生成
また、インスタンスを生成する際もnewは不要になります。
// 'new'は不要
val player = Player("Alice", 10)
// プロパティへのアクセス(内部的にgetter/setterが呼ばれる)
println(player.name) // getter呼び出し
player.level = 11 // setter呼び出し(levelフィールドはvarのため、setterも呼び出し可能)
補足:フィールドとプロパティの違い
- フィールド (Field): データを保存するための「物理的な箱(メモリ領域)」
- プロパティ (Property): フィールドと、それにアクセスするための「Getter / Setter メソッド」をひとまとめにした概念
2.2 クラス本体 {} の役割
メソッドの定義や、より複雑なプロパティ、初期化ロジックはクラス本体{…}の中に記述します。
- メソッド: Javaと同様に、クラスの振る舞いを定義します。
- initブロック: プライマリコンストラクタの一部として、オブジェクト生成時に実行される初期化コードを記述します。
Javaでいうところのコンストラクタです。
Javaでコンストラクタの中に記述していたロジックは、Kotlinではinitブロックの中に記述する感じです。 - 追加のプロパティ: コンストラクタ引数に頼らないプロパティ(固定値を持つ、他のプロパティから計算されるなど)を定義します。
class Player(val name: String, var level: Int) {
// 初期化ブロック
init {
// オブジェクト生成時に実行される
require(level > 0) { "Level must be positive." }
}
// メソッド
fun levelUp() {
level++
}
}
3. 学習中のQ&A
本トピックの学習を進めるうえで私がGeminiに対して投げた質問とそれに対する回答をまとめました。
Q. getter/setterが自動生成されるなら、privateやpublicといったアクセス制御はどう行うのですか?
Geminiの回答:プロパティのgetter/setterの可視性は個別に設定可能です。特に「読み取りは公開、書き込みはクラス内に限定したい」場合はprivate setを使用します。これにより、カプセル化を維持できます。
class Player(val name: String) {
// 外部からは「読む」ことしかできず、
// 書き換え(セット)はこのクラスの内部からしかできないプロパティ
var score: Int = 0
private set
// スコアを増やす公式な手順(メソッド)
fun playData(points: Int) {
if (points > 0) {
score += points // 内部からなのでset可能
println("${name}が${points}ポイント獲得しました!")
}
}
}Q. private setのようなカスタマイズをすると、クラス定義は1行で書けなくなるのですか?
Geminiの回答:はい、その通りです。private setのようにgetter/setterを個別にカスタマイズする場合、プロパティをクラス本体{}内で定義する必要があります。最もシンプルなケースは1行で、複雑な制御が必要な場合はクラス本体に記述する、という柔軟な設計になっています。
Q. プロパティ(フィールド)はクラス本体{}内には宣言しないのですか?
Geminiの回答:「しない」わけではなく、役割分担があります。
インスタンス化に必須で外部から値を受け取るプロパティはプライマリコンストラクタ(…)内に、
それ以外の追加のプロパティ(内部で使うprivateなもの、固定値を持つもの、他のプロパティから計算されるものなど)はクラス本体{}内に宣言するのが一般的です。
Q. ファイル名とクラス名は、Javaのように一致させる必要がありますか?
Geminiの回答:いいえ、その必要はありません。Kotlinでは1つのファイルに複数のpublicクラスを定義することも可能です。ただし、ファイルにpublicクラスが1つしかないのであれば、Javaと同様にクラス名とファイル名を一致させるのが一般的な習慣(ベストプラクティス)です。
4. まとめ
本記事ではKotlinのクラス定義について解説しました。
KotlinのクラスはJavaの定型的なコードを大幅に削減し、開発者の意図をより直接的に表現できるよう設計されています。
- プライマリコンストラクタとプロパティの仕組みにより、データ保持クラスを非常に簡潔に記述できる。
- クラスの振る舞いや追加のロジックは、必要に応じてクラス本体(”{}”の中)に記述する。
- カプセル化のためのアクセス制御も、簡潔な構文で柔軟に行える。
これらの特徴を理解することが、Kotlinにおけるオブジェクト指向プログラミングの第一歩となります。
コメント