Skip to content
Playground

演習: データクラス

各問題ごとに .java ファイルを作り、Main.java で動作確認します。

点数を表す Score クラスを Score.java に定義してください。次のとおり定義します。

  • フィールド: value(int、private final
  • コンストラクターで初期値を受け取る。0 未満または 100 より大きい場合は 不正な点数: 値 を出力して 0 を代入する
  • getValue(): 現在の value を返す
Main.java
System.out.println(new Score(85).getValue());
System.out.println(new Score(-10).getValue());
System.out.println(new Score(120).getValue());

出力例:

85
不正な点数: -10
0
不正な点数: 120
0
ヒント

不正値の扱い方は本文 settersetAge 例と同じパターンです。if で範囲を判定し、不正なら System.out.println でメッセージを出してから this.value = 0; を実行します。final フィールドはコンストラクター内で 1 回だけ代入できるので、if-else で正常値と 0 を振り分けます。

演習 1-C で作った Point クラスを開き、フィールド xyprivate final に変更してください。getX()getY() を追加し、setter は作りません(座標は作成後に変更しない設計)。

Main.java
Point p = new Point(3, 5);
System.out.println(p.getX());
System.out.println(p.getY());

出力例:

3
5
ヒント

本文 getter を参照します。final を付けたフィールドはコンストラクターでの初期化後に書き換えられないので、setter を作らない選択と相性が良い設計です。

演習 1-E で作った Person クラスを開き、nameprivate finalageprivate にしてください。getName() / getAge()setAge(int) を追加します。setAge では 0 未満の値を受け取ったときに 不正な年齢: 値 を出力して何もしません(年齢は元の値のまま)。setName は作りません(namefinal のため書き換え不可、本文 完成形のコード と同じ構成)。

Main.java
Person p = new Person("田中", 25);
p.setAge(26);
System.out.println(p.getAge());
p.setAge(-5);
System.out.println(p.getAge());

出力例:

26
不正な年齢: -5
26
ヒント

本文 settersetAge 例と同じパターンです。introduce() メソッドは残したままで構いません(メソッドの中ではフィールドに直接アクセスできるので、書き換える必要はありません)。

2-D. Point に move と distanceTo を追加

Section titled “2-D. Point に move と distanceTo を追加”

2-B で作った Point に、不変設計のメソッドを 2 つ追加してください。次のとおり実装します。

  • move(int dx, int dy): x + dxy + dy の座標を持つ新しい Point を返す。元のインスタンスは変えない
  • distanceTo(Point other): 引数の Point までの距離(double)を返す。距離は Math.sqrt((x - other.x)² + (y - other.y)²)
Main.java
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, 0
3, 4
5.0

a.move(3, 4) を呼んだあとも a(0, 0) のままです。Point を変更したいときは新しいインスタンスを受け取って使います。

ヒント

不変クラスでの変更は、新しいインスタンスを生成して返す形で表現します。move の中では return new Point(x + dx, y + dy); のように書きます。final フィールドのまま値を変えずに済みます。

distanceTo の中では this.x - other.x のように、自分のフィールドと引数のフィールドを使い分けます(同じ Point クラスなので other.x で直接アクセスできます)。

商品を表すデータクラス ItemItem.java に定義してください。次のとおり定義します。

  • フィールド: name(String、final)、price(int、final)、stock(int、可変)
  • コンストラクターで price0 未満なら 不正な価格: 値 を出力して 0 を代入。stock0 未満なら 不正な在庫: 値 を出力して 0 を代入
  • getter は 3 つすべて用意する
  • setStock は作らない(在庫変更は専用メソッド経由)
  • reduceStock(int quantity): 在庫を quantity 個減らす
    • quantity0 未満なら 数量は 0 以上にしてください: 値 を出力して何もしない
    • quantity が現在の stock を超えるなら 在庫不足: stock=現在値, quantity=値 を出力して何もしない
    • 上記以外なら stock を減らす
  • addStock(int quantity): 在庫を quantity 個増やす
    • quantity0 未満なら 数量は 0 以上にしてください: 値 を出力して何もしない
    • そうでなければ stock を増やす
Main.java
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
ヒント

reduceStockaddStock は本文 setter の検査パターンを応用します。if で不正値を弾き、System.out.println でメッセージを出してから return; で処理を止めます。

pricefinal にする選択は「商品の値段は作成後に変えない」という設計判断です。値上げをしたい場合は新しい Item インスタンスを作る運用になります。

学生の成績を表す Student クラスを Student.java に定義してください。次のとおり定義します。

  • フィールド: name(String)、scoresList<Integer>)。両方とも private final
  • コンストラクターで両方を受け取り、フィールドにそのまま代入する(受け取った List をそのまま保持してよい)
  • getter は getName() のみ用意する
  • average(): 平均点(double)を返す。scores が空のときは 0.0 を返す
  • max(): 最高点(int)を返す。scores が空のときは 0 を返す
Main.java
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 にキャストします。