Day 6: クラスとオブジェクト
今日学ぶこと
- クラスとオブジェクトの基本
- フィールドとメソッド
- コンストラクタ
- アクセス修飾子
- static メンバー
- レコード(Java 16+)
クラスとオブジェクト
クラスは設計図、オブジェクトは設計図から作った実体です。
// クラスの定義(設計図)
public class Dog {
// フィールド(属性)
String name;
int age;
// メソッド(振る舞い)
void bark() {
System.out.println(name + ": ワン!");
}
}
// オブジェクトの生成(実体化)
Dog dog1 = new Dog();
dog1.name = "ポチ";
dog1.age = 3;
dog1.bark(); // ポチ: ワン!
flowchart LR
subgraph Class["クラス(設計図)"]
CD["Dog<br>name, age<br>bark()"]
end
subgraph Objects["オブジェクト(実体)"]
O1["dog1<br>ポチ, 3歳"]
O2["dog2<br>タロウ, 5歳"]
end
Class -->|"new"| O1
Class -->|"new"| O2
style CD fill:#3b82f6,color:#fff
style O1 fill:#22c55e,color:#fff
style O2 fill:#22c55e,color:#fff
コンストラクタ
オブジェクト生成時に呼ばれる初期化用メソッドです。
public class Dog {
String name;
int age;
// コンストラクタ
Dog(String name, int age) {
this.name = name; // this = このオブジェクト
this.age = age;
}
void introduce() {
System.out.printf("%s(%d歳)%n", name, age);
}
}
// 使用
Dog dog = new Dog("ポチ", 3);
dog.introduce(); // ポチ(3歳)
コンストラクタのオーバーロード
public class Dog {
String name;
int age;
String breed;
// 全引数コンストラクタ
Dog(String name, int age, String breed) {
this.name = name;
this.age = age;
this.breed = breed;
}
// 名前と年齢のみ
Dog(String name, int age) {
this(name, age, "不明"); // 別のコンストラクタを呼ぶ
}
// 名前のみ
Dog(String name) {
this(name, 0, "不明");
}
}
ポイント:
this()で同じクラスの別のコンストラクタを呼び出せます。これをコンストラクタチェーンと呼びます。
アクセス修飾子
public class BankAccount {
private String owner;
private double balance;
public BankAccount(String owner, double initialBalance) {
this.owner = owner;
this.balance = initialBalance;
}
// getter
public double getBalance() {
return balance;
}
// 入金
public void deposit(double amount) {
if (amount > 0) {
balance += amount;
}
}
// 出金
public boolean withdraw(double amount) {
if (amount > 0 && amount <= balance) {
balance -= amount;
return true;
}
return false;
}
}
| 修飾子 | クラス内 | 同パッケージ | サブクラス | どこからでも |
|---|---|---|---|---|
private |
✅ | ❌ | ❌ | ❌ |
| (なし) | ✅ | ✅ | ❌ | ❌ |
protected |
✅ | ✅ | ✅ | ❌ |
public |
✅ | ✅ | ✅ | ✅ |
flowchart TB
subgraph Access["アクセス修飾子の範囲"]
Private["private<br>クラス内のみ"]
Default["(なし)<br>同パッケージ"]
Protected["protected<br>+ サブクラス"]
Public["public<br>どこからでも"]
end
Private --> Default --> Protected --> Public
style Private fill:#ef4444,color:#fff
style Default fill:#f59e0b,color:#fff
style Protected fill:#3b82f6,color:#fff
style Public fill:#22c55e,color:#fff
原則: フィールドは
privateにし、必要に応じてgetter/setterを提供します(カプセル化)。
getter / setter
public class Student {
private String name;
private int score;
public Student(String name, int score) {
this.name = name;
setScore(score);
}
// getter
public String getName() { return name; }
public int getScore() { return score; }
// setter(バリデーション付き)
public void setScore(int score) {
if (score >= 0 && score <= 100) {
this.score = score;
} else {
throw new IllegalArgumentException("スコアは0〜100の範囲です");
}
}
}
static メンバー
staticはクラスに属する(オブジェクトに属さない)メンバーです。
public class Counter {
private static int count = 0; // 全オブジェクトで共有
private String name;
Counter(String name) {
this.name = name;
count++;
}
// staticメソッド
static int getCount() {
return count;
}
void show() {
System.out.printf("%s (total: %d)%n", name, count);
}
}
// 使用
Counter a = new Counter("A");
Counter b = new Counter("B");
Counter c = new Counter("C");
System.out.println(Counter.getCount()); // 3
| 種類 | 所属 | アクセス方法 |
|---|---|---|
| インスタンスメンバー | オブジェクト | obj.method() |
| staticメンバー | クラス | ClassName.method() |
注意:
staticメソッドからthisや非staticメンバーにはアクセスできません。
toString メソッド
オブジェクトの文字列表現をカスタマイズします。
public class Dog {
private String name;
private int age;
Dog(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return String.format("Dog{name='%s', age=%d}", name, age);
}
}
Dog dog = new Dog("ポチ", 3);
System.out.println(dog); // Dog{name='ポチ', age=3}
レコード(Java 16+)
データを保持するだけのクラスを簡潔に定義できます。
// 従来のクラス(ボイラープレートが多い)
public class Point {
private final int x;
private final int y;
Point(int x, int y) { this.x = x; this.y = y; }
int x() { return x; }
int y() { return y; }
// + equals, hashCode, toString...
}
// レコード(1行で同等の機能)
record Point(int x, int y) {}
レコードは自動的に以下を生成します:
- コンストラクタ
- アクセサメソッド(
x(),y()) equals(),hashCode(),toString()
record Student(String name, int score) {
// カスタムメソッドも追加可能
String grade() {
if (score >= 90) return "A";
if (score >= 80) return "B";
if (score >= 70) return "C";
return "D";
}
}
var s = new Student("太郎", 85);
System.out.println(s.name()); // 太郎
System.out.println(s.score()); // 85
System.out.println(s.grade()); // B
System.out.println(s); // Student[name=太郎, score=85]
推奨: データを保持するだけのクラスにはレコードを使いましょう。
実践: 銀行口座システム
public class BankAccount {
private static int nextId = 1;
private final int id;
private String owner;
private double balance;
public BankAccount(String owner, double initialBalance) {
this.id = nextId++;
this.owner = owner;
this.balance = initialBalance;
}
public BankAccount(String owner) {
this(owner, 0);
}
public void deposit(double amount) {
if (amount <= 0) {
System.out.println("入金額は正の数を指定してください。");
return;
}
balance += amount;
System.out.printf("[口座%d] %,.0f円 入金 → 残高: %,.0f円%n", id, amount, balance);
}
public boolean withdraw(double amount) {
if (amount <= 0 || amount > balance) {
System.out.println("出金できません。");
return false;
}
balance -= amount;
System.out.printf("[口座%d] %,.0f円 出金 → 残高: %,.0f円%n", id, amount, balance);
return true;
}
public void transfer(BankAccount to, double amount) {
if (this.withdraw(amount)) {
to.deposit(amount);
System.out.printf("→ %sから%sへ %,.0f円 送金完了%n", this.owner, to.owner, amount);
}
}
@Override
public String toString() {
return String.format("口座%d: %s (残高: %,.0f円)", id, owner, balance);
}
public static void main(String[] args) {
var alice = new BankAccount("Alice", 100000);
var bob = new BankAccount("Bob", 50000);
System.out.println(alice);
System.out.println(bob);
System.out.println();
alice.deposit(30000);
bob.withdraw(10000);
alice.transfer(bob, 25000);
System.out.println();
System.out.println(alice);
System.out.println(bob);
}
}
まとめ
| 概念 | 説明 |
|---|---|
| クラス | オブジェクトの設計図 |
| オブジェクト | クラスから生成された実体 |
| コンストラクタ | 初期化処理 |
this |
現在のオブジェクトへの参照 |
| アクセス修飾子 | private / protected / public |
| カプセル化 | フィールドをprivateにして保護 |
static |
クラスに属するメンバー |
| レコード | データ保持用の簡潔なクラス(Java 16+) |
重要ポイント
- フィールドは**
private**にする(カプセル化) - コンストラクタでオブジェクトを適切に初期化
- **
static**メンバーはクラス全体で共有 - データクラスにはレコードを使う
練習問題
問題1: 基本
Bookクラス(タイトル、著者、ページ数)を作成し、複数の本を作って情報を表示してください。
問題2: 応用
ShoppingCartクラスを作成してください。商品の追加・削除・合計金額計算ができるようにしましょう。
チャレンジ問題
recordを使ってMoneyレコード(金額、通貨)を定義し、同じ通貨同士の加算・減算メソッドを実装してください。異なる通貨の場合はエラーにしましょう。
参考リンク
次回予告: Day 7では「継承とポリモーフィズム」について学びます。クラスの拡張と再利用の仕組みをマスターしましょう。