演習: データクラス
各問題ごとに .java ファイルを作り、Main.java で動作確認します。
2-A. Score の定義
Section titled “2-A. Score の定義”点数を表す Score クラスを Score.java に定義してください。次のとおり定義します。
- フィールド:
value(int、private final) - コンストラクターで初期値を受け取る。
0未満または100より大きい場合は不正な点数: 値を出力して0を代入する getValue(): 現在のvalueを返す
System.out.println(new Score(85).getValue());System.out.println(new Score(-10).getValue());System.out.println(new Score(120).getValue());出力例:
85不正な点数: -100不正な点数: 1200ヒント
不正値の扱い方は本文 setter の setAge 例と同じパターンです。if で範囲を判定し、不正なら System.out.println でメッセージを出してから this.value = 0; を実行します。final フィールドはコンストラクター内で 1 回だけ代入できるので、if-else で正常値と 0 を振り分けます。
2-B. Point に private + getter
Section titled “2-B. Point に private + getter”演習 1-C で作った Point クラスを開き、フィールド x、y を private final に変更してください。getX() と getY() を追加し、setter は作りません(座標は作成後に変更しない設計)。
Point p = new Point(3, 5);System.out.println(p.getX());System.out.println(p.getY());出力例:
35ヒント
本文 getter を参照します。final を付けたフィールドはコンストラクターでの初期化後に書き換えられないので、setter を作らない選択と相性が良い設計です。
2-C. Person に private + getter/setter
Section titled “2-C. Person に private + getter/setter”演習 1-E で作った Person クラスを開き、name を private final、age を private にしてください。getName() / getAge() と setAge(int) を追加します。setAge では 0 未満の値を受け取ったときに 不正な年齢: 値 を出力して何もしません(年齢は元の値のまま)。setName は作りません(name は final のため書き換え不可、本文 完成形のコード と同じ構成)。
Person p = new Person("田中", 25);p.setAge(26);System.out.println(p.getAge());
p.setAge(-5);System.out.println(p.getAge());出力例:
26不正な年齢: -526ヒント
本文 setter の setAge 例と同じパターンです。introduce() メソッドは残したままで構いません(メソッドの中ではフィールドに直接アクセスできるので、書き換える必要はありません)。
2-D. Point に move と distanceTo を追加
Section titled “2-D. Point に move と distanceTo を追加”2-B で作った Point に、不変設計のメソッドを 2 つ追加してください。次のとおり実装します。
move(int dx, int dy):x + dx、y + dyの座標を持つ新しいPointを返す。元のインスタンスは変えないdistanceTo(Point other): 引数のPointまでの距離(double)を返す。距離はMath.sqrt((x - other.x)² + (y - other.y)²)
Point a = new Point(0, 0);Point b = a.move(3, 4);
System.out.println(a.getX() + ", " + a.getY()); // a は変わらないSystem.out.println(b.getX() + ", " + b.getY()); // b は移動後の座標System.out.println(a.distanceTo(b));出力例:
0, 03, 45.0a.move(3, 4) を呼んだあとも a は (0, 0) のままです。Point を変更したいときは新しいインスタンスを受け取って使います。
ヒント
不変クラスでの変更は、新しいインスタンスを生成して返す形で表現します。move の中では return new Point(x + dx, y + dy); のように書きます。final フィールドのまま値を変えずに済みます。
distanceTo の中では this.x - other.x のように、自分のフィールドと引数のフィールドを使い分けます(同じ Point クラスなので other.x で直接アクセスできます)。
2-E. Item の在庫管理
Section titled “2-E. Item の在庫管理”商品を表すデータクラス Item を Item.java に定義してください。次のとおり定義します。
- フィールド:
name(String、final)、price(int、final)、stock(int、可変) - コンストラクターで
priceが0未満なら不正な価格: 値を出力して0を代入。stockが0未満なら不正な在庫: 値を出力して0を代入 - getter は 3 つすべて用意する
setStockは作らない(在庫変更は専用メソッド経由)reduceStock(int quantity): 在庫をquantity個減らすquantityが0未満なら数量は 0 以上にしてください: 値を出力して何もしないquantityが現在のstockを超えるなら在庫不足: stock=現在値, quantity=値を出力して何もしない- 上記以外なら
stockを減らす
addStock(int quantity): 在庫をquantity個増やすquantityが0未満なら数量は 0 以上にしてください: 値を出力して何もしない- そうでなければ
stockを増やす
Item apple = new Item("りんご", 150, 10);
apple.reduceStock(3);System.out.println("在庫: " + apple.getStock());
apple.reduceStock(20);System.out.println("在庫: " + apple.getStock());
apple.addStock(5);System.out.println("在庫: " + apple.getStock());
apple.addStock(-1);System.out.println("在庫: " + apple.getStock());出力例:
在庫: 7在庫不足: stock=7, quantity=20在庫: 7在庫: 12数量は 0 以上にしてください: -1在庫: 12ヒント
reduceStock と addStock は本文 setter の検査パターンを応用します。if で不正値を弾き、System.out.println でメッセージを出してから return; で処理を止めます。
price を final にする選択は「商品の値段は作成後に変えない」という設計判断です。値上げをしたい場合は新しい Item インスタンスを作る運用になります。
2-F. Student の集計メソッド
Section titled “2-F. Student の集計メソッド”学生の成績を表す Student クラスを Student.java に定義してください。次のとおり定義します。
- フィールド:
name(String)、scores(List<Integer>)。両方ともprivate final - コンストラクターで両方を受け取り、フィールドにそのまま代入する(受け取った
Listをそのまま保持してよい) - getter は
getName()のみ用意する average(): 平均点(double)を返す。scoresが空のときは0.0を返すmax(): 最高点(int)を返す。scoresが空のときは0を返す
import java.util.ArrayList;import java.util.List;
List<Student> students = new ArrayList<>();
List<Integer> tanakaScores = new ArrayList<>();tanakaScores.add(70);tanakaScores.add(85);tanakaScores.add(90);students.add(new Student("田中", tanakaScores));
List<Integer> suzukiScores = new ArrayList<>();suzukiScores.add(60);suzukiScores.add(75);students.add(new Student("鈴木", suzukiScores));
for (Student s : students) { System.out.println(s.getName() + ": 平均=" + s.average() + ", 最高=" + s.max());}出力例:
田中: 平均=81.66666666666667, 最高=90鈴木: 平均=67.5, 最高=75ヒント
List<Integer> の合計や最大は、拡張 for 文で 1 要素ずつ取り出して計算します。
int sum = 0;for (int s : scores) { sum += s;}for (int s : scores) は Integer を自動的に int に変換します(オートアンボクシング)。
平均は double で返すので、(double) sum / scores.size() のように片方を double にキャストします。