平成28年春期試験午前問題 午後問11

問11 ソフトウェア開発(Java)

次のJavaプログラムの説明及びプログラムを読んで,設問1,2に答えよ。
(Javaプログラムで使用するAPIの説明は,こちらを参照してください。)

〔プログラムの説明〕
 "すべきこと"(以下,ToDo という)を管理するプログラムである。
  • クラス ToDo は ToDo を表すクラスであり,コンストラクタで主題,期限,重要度を指定する。期限は,年月日を表す8桁又は年月日時分を表す12桁の数字から成る文字列(以下,日時という)であり,例えば,2016年4月16日を表す文字列は"20160416",2016年4月16日午後1時0分を表す文字列は"201604161300"である。ここで,日時に誤りはないものとする。
     主題,期限,重要度を取得する各メソッドと,状態を設定及び取得するメソッド,ToDo を識別するフィールド id をもつ。
     列挙 Priority は ToDo の重要度を表す列挙であり,重要度が低い順に LOW,MIDDLE,HIGH である。
     列挙 State は ToDo の状態を表す列挙であり,NOT_YET_STARTED は未着手,STARTED は着手済み,DONE は完了を表す。
  • クラス ToDoList は ToDo のリストを保持するクラスである。
     リスト中に,フィールド id の値が同じ ToDo を複数個含まないことを保証する。
     ToDo を追加するメソッド add と,ToDo の更新を行うメソッド update,条件に合う ToDo のリストを返すメソッド select をもつ。
     メソッド add の引数に,既にリストに保持されている ToDo を指定したとき,及びメソッド update の引数に,リストにない ToDo を指定したときは何もしない。
     メソッド setect の引数には,条件を0個以上指定できる。条件を指定したときは,全ての条件に合致する ToDo から成るリストを返す。条件を指定しないときは,保持する全ての ToDo から成るリストを返す。
  • インタフェース Condition は,ToDo を選択する際の条件を表すクラスが実装するインタフェースである。メソッド test は条件に合致するときに true を返す。
  • クラス ToDoListTester は,テスト用のクラスである。
pm11_1.gif

設問1

プログラム中の に入れる正しい答えを,解答群の中から選べ。
a に関する解答群
  • ((ToDo) o).id.equals(id)
  • (ToDo) o.id.equals(id)
  • id.equals(id)
  • o.id.equals(id)
b に関する解答群
  • !todoList.contains(todo)
  • !todoList.isEmpty()
  • todoList.contains(todo)
  • todoList.isEmpty()
c に関する解答群
  • != -1
  • < todoList.size()
  • == -1
  • >= todoList.size()
d に関する解答群
  • boolean selected = false
  • boolean selected = true
  • int selecte = 0
  • int selected = todoList.size()
e に関する解答群
  • +=
  • =
  • ==
  • |=
解答選択欄
  • a:
  • b:
  • c:
  • d:
  • e:
  • a=
  • b=
  • c=
  • d=
  • e=

解説

aについて〕
equals メソッドは、インスタンス同士が等価であるかどうかを判定するメソッドです。選択肢を見ると、引数 o がもつ id と、自身の id を比較することで判定しています。ここでは、Object型の引数 o について id を参照する方法が問われています。

id はToDoクラスで独自に定義したメンバ変数であり、Object型のままでは id を参照できません。このような時には、o をToDo型にキャスト(型変換)してあげる必要があります。

Javaでは明示的にインスタンスの型変換を行う場合、以下の記法を使います。上位クラスから下位クラスに変換するダウンキャストでは明示的に型変換を行わなければなりません。
(変換後の型名) 変換元の変数
また、キャストした変数のメンバ変数を参照したり、メンバメソッドを呼び出したりするには、
(ToDo) o.メソッド名
ではなく、これをさらに()で囲って、
((ToDo) o).メソッド名
としなければなりません。

a=ア:((ToDo) o).id.equals(id)
  • 正しい。
  • 上記のルールに則っていないため文法上不適切です。
  • 文法上は正しいですが、同じメンバ変数同士の比較となっており処理の意味がないので不適切です。
  • 「イ」と同じ理由で不適切です。
bについて〕
どの選択肢も文法上は正しいので、add メソッドの意味合いから解答を判断します。

〔プログラムの説明〕(2)では、add を「ToDoを追加するメソッド」と説明しています。クラス ToDoList は「リスト中にフィールド id の値が同じToDoを複数含まない」という条件があるので、リストに追加する前に、同じToDoがリスト中に存在しないことを確認する必要があります。List型のメソッド contains は、指定された要素がリスト内にあればtrueを返すので、追加対象のToDoである todo を引数にして contains を呼び出し、falseが返ってくればリスト内に同じToDoがないと判断できます。

contains の返り値がfalseのときに真となる条件式にしたいので、結果の真偽を反転する"!"を付けた「ア」が適切です。

b=!todoList.contains(todo)
  • 正しい。
  • isEmpty はリストが空かどうかを判定するメソッドです。id の値が同じToDoが存在しているかどうかの判定とならないので不適切です。
  • 「リストに同じ id のToDoが存在している」場合に、追加することになってしまうので不適切です。
  • 「イ」と同じ理由で不適切です。
cについて〕
〔プログラムの説明〕(2)では、update を「ToDoの更新を行うメソッド」と説明しています。更新処理には、「リストにないToDoを指定したときは何もしない」という条件があるので、更新の前に、引数の todo がリスト内に存在していることを確認する必要があります。List型のメソッド indexOf は、指定された要素がリスト内に存在すればそのインデックス(0以上)を、存在しなければ-1を返すので、更新対象のToDoである todo を引数として indexOf を呼び出し、-1以外が返ってくればリスト内にそのToDoが存在すると判断できます。

indexOf の返り値は変数 index に格納されているため、index が-1ではないときに真となる「ア」が適切です。その後、index の値は、set メソッドで更新対象のToDoの位置を指定するために使われています。

c=ア:!= -1
  • 正しい。
  • size メソッドはリストの要素数を返します。変数 index の値は「要素数 - 1」を超えることはありませんから、常に更新処理が実行されてしまいます。
  • 指定されたToDoがリストに「存在しない」場合に更新処理が実行されてしまうので不適切です。
  • 「イ」と同様の理由で、常に更新処理が実行されないので不適切です。

dについて〕
選択肢の内容から判断して、変数 selected の型と初期値を答える問題です。

まず型についてですが、Javaではif文内の式は必ずboolean型である必要があります(Cやインタプリタ言語のように暗黙的型変換が行われない)。selected は、if文の条件でそのまま使われていることからboolean型の変数であると判断できます。

次は selected の初期値です。boolean型ですので true または false になります。
[d]を含むforループの処理を確認すると、ToDoリストの要素を1つずつ見ていき、可変長引数として与えられる絞り込み条件 conditions にすべて合致する場合に、戻り値 result に要素を追加していく処理であると考えられます。ここで「メソッド setect の引数には,条件を0個以上指定できる。(中略)条件を指定しないときは,保持する全ての ToDo から成るリストを返す。」という説明に注目すると、conditions が0個でforループが全く実行されないケースがあることがわかります。

このとき、
if (selected) {
 result.add(new ToDo(todo));
}
の処理で selected は初期値のままです。条件の指定がない場合は、全てのToDoを result に追加する必要があるので、selectedの値は true になっていなければなりません。これより、selected の初期値はtrueだとわかります。

d=イ:boolean selected = true

eについて〕
condition は Condition 型の変数で、「メソッド test は条件に合致するときに true を返す。」と説明されています。for文では各ToDoに対して conditions の各要素の test メソッドを呼び出していて、これは当該ToDoが全ての条件に合致するかどうかを判定する処理に当たります。test メソッドがfalseを返したときは条件に合致しなかったことを意味するので、その場合は selected にfalseを設定し、追加対象から除外する必要があります。よって、メソッド test の返り値をそのまま selected に代入する「=」の演算子が適切です。

e=イ:=
  • boolean型に対して使えない演算子なので不適切です。
  • 正しい。
  • 代入ではなく比較の演算子なので selected の値は更新されません。selected の値がtrueのまま変わらないので不適切です。
  • 右辺の値との論理和を左辺に代入する演算子です。左辺 selected の初期値は true ですので、test の返り値にかかわらず selected にはtrueが設定されてしまいます。

設問2

プログラム4の実行結果を図1に示す。 に入れる正しい答えを,解答群の中から選べ。
pm11_2.gif
f,g に関する解答群
  • 主題: PC購入,期限: 20160531,優先度: HIGH
  • 主題: 会議室予約,期限: 201605301200,優先度: HIGH
  • 主題: チケット購入,期限: 20160430,優先度: MIDDLE
  • 主題: 報告書作成,期限: 20160428,優先度: HIGH
  • 主題: ホテル予約,期限: 20160420,優先度: LOW
  • 主題: メール送信,期限: 201604181500,優先度: HIGH
解答選択欄
  • f:
  • g:
  • f=
  • g=

解説

メソッド select の引数となっている condition1、condition2 の test メソッドの内容を確認すると、以下のようになっています。
//condition1
return todo.getDeadline().compareTo("20160501") < 0;
//condition2
return todo.getPriority().equals(ToDo.Priority.HIGH);
condition1 では、日時が"20160501"より前のもの、condition2 では、優先度が HIGH のものを絞り込み条件にしていることがわかります。条件を指定したときは、全ての条件に合致するToDoから成るリストを返すので、select を呼び出すと list に登録したToDoのうち、条件に合致した以下の2つのToDoがリストとして返されます。
pm11_3.gif
for文では select メソッドが返したリストの要素ごとに println を実行していますが、select メソッドでは先頭のToDoから順に走査しているので、返り値のリストでも従前の順番は保たれたままです。よって、先に登録されたToDoほど先に出力されることになります。よって、[f]が「メール送信…」、[g]が「報告書作成…」となります。

f=カ:主題: メール送信,期限: 201604181500,優先度: HIGH
 g=エ:主題: 報告書作成,期限: 20160428,優先度: HIGH

なお、日時の桁数には8桁と12桁がありますが、compareTo メソッドは数値としてではなく辞書順で比較するので、どちらでも問題なく日時の前後が判定できます。

Pagetop