基本情報技術者 2012年 春期 午後 問11
次のJavaプログラムの説明及びプログラムを読んで、設問1,2に答えよ。
〔プログラムの説明〕
試験の成績を管理するプログラムである。
(1) クラスScoreManagerは、後述するクラスValueSortedMapを継承したクラスで、試験の成績を管理する。点数の高い順に学籍番号(英数字で構成される固定長の文字列)と点数を出力するメソッドprintをもつ。
(2) クラスValueSortedMapは、キーと値の対応付けを値の昇順、又はコンストラクタで指定したコンパレータに従った順に保持する。キーと値の対応付けをキーの昇順、又はコンパレータに従った順に保持するクラスTreeMapを利用している。主なメソッドは次のとおりである。
public V put(K key, V value)
keyにvalueを対応付けて登録する。key又はvalueがnullのときは例外NullPointerExceptionを投げる。keyが既に他の値と対応付けられていれば、その値をvalueで置き換え、置き換えられる前の値を返す。keyに値が対応付けられていなければ、nullを返す。
public V get(K key)
keyに対応付けられた値を返す。keyと値の対応付けがなければ、nullを返す。
public V remove(K key)
keyと値の対応付けを削除し、対応付けられていた値を返す。keyと値の対応付けがなければ、nullを返す。
public Iterator iterator()
対応付けられた値の昇順、又はコンストラクタで指定したコンパレータに従った順に、キーを返すための反復子を返す。
フィールドmapは、キーと値の対応付けを保持する。
フィールドreverseMapは、値にキーを対応付けて保持する。異なるキーに同じ値が対応付けられることがあるので、値に対応付けられるのはキーのリストである。
(3) クラスScoreManagerTesterは、成績管理プログラムのテストプログラムである。メソッドmainの実行結果を、図1に示す。




設問1:
問題文を見る プログラム中のに入れる正しい答えを、解答群の中から選べ。
aに関する解答群
ア:Integer
イ:Integer, String
ウ:String
エ:String, Integer
bに関する解答群
ア:key != null && value != null
イ:key != null || value != null
ウ:key == null && value == null
エ:key == null || value == null
cに関する解答群
ア:!keys.isEmpty()
イ:keys != null
ウ:keys == null
エ:keys.isEmpty()
d, eに関する解答群
ア:Map.get
イ:map.get
ウ:Map.remove
エ:map.remove
オ:remove
カ:reverseMap.get
キ:reverseMap.remove
模範解答
a:エ、b:エ、c:ウ、d:エ、e:キ
解説
解答の導き方
この問題では、成績を「学籍番号」と「点数」の組として管理し、点数の高い順に取り出す仕組みを完成させます。まず、クラスで扱うキーと値の型を確認し、その後、登録・削除の処理を見ていきます。
a:キーと値の型を決めます
ValueSortedMapは、クラスの宣言がValueSortedMap<K, V> です。Kがキーの型、Vが値の型です。また、putの引数は「K key, V value」の順です。
ScoreManagerでは、学籍番号をキー、点数を値として扱います。学籍番号は文字列なのでキーはStringです。点数は整数なので値はIntegerです。したがって、継承時の型は <String, Integer> となります。
b:nullを受け付けない条件を決めます
putの説明には、キーまたは値がnullのときにNullPointerExceptionを投げるとあります。つまり、キーがnullの場合と、値がnullの場合のどちらでも例外にする必要があります。
どちらか一方でも当てはまる条件は「key == null || value == null」です。ここで「||」は、左右のどちらかが成り立てば全体が成り立つ、という意味です。
c:値に対応するキーのリストがない場合を処理します
reverseMapは、値に対応するキーのリストを保持します。putで値に対応するリストを取り出したとき、その値がまだ登録されていなければ、リストは見つからずkeysはnullになります。
その場合は新しいリストを作り、reverseMapに登録する必要があります。したがって、調べる条件は「keys == null」です。リストが見つかった場合は、新しいリストを作らず、そこにキーを追加します。
d:キーと値の対応付けを削除します
removeでは、最初に指定されたキーに対応する値を取り出します。同時に、キーと値の対応付け自体も削除する必要があります。
その対応付けを保持しているのはmapです。したがって、mapからキーを削除し、削除前の値を受け取るmap.remove(key) を使います。map.get(key)では値を調べるだけで、対応付けは削除されません。
その後、reverseMapからもキーを取り除きます。対応するキーが一つも残らなくなった場合は、値に対応するリストそのものをreverseMapから削除する必要があります。
e:reverseMapから値とリストの対応付けを削除します
keysが空になったときは、そのリストをreverseMapに残しておく必要がありません。削除対象は値に対応するリストなので、reverseMapからvalueを削除します。使うのはreverseMap.remove(value) です。
ここまでの考えを、mainの処理に当てはめます。コンストラクタでは、値を比較する規則であるコンパレータに「b.compareTo(a)」を指定しています。比較する順序を逆にするため、点数は高い順に並びます。同じ点数のキーはリストに追加された順に取り出されます。
FE0001の点数を70から85に変更するとき、putはまず古い対応付けをremoveで削除し、その後、新しい値に登録します。そのため、85のリストでは、先に登録されていたFE0003の後にFE0001が並びます。
続く「sm.put(null, 90)」では、キーがnullなので例外が発生します。例外はtryの中で捕捉されますが、例外が発生した時点でtryの残りの処理は実行されません。そのため、次の「sm.put("FE0004", 90)」は実行されず、FE0004は削除されたままです。
この結果、printでは90点、85点の順に出力されます。90点の中ではFE0002、FE0005の順、85点の中ではFE0003、FE0001の順です。最後のgetでは、削除後に再登録されなかったFE0004の値を調べるため、nullが表示されます。これは図1の実行結果と一致します。
誤りやすいポイント
- ValueSortedMap<K, V>では、Kがキー、Vが値です。学籍番号と点数の順を逆にしないようにします。
- nullの検査では、キーと値の両方を同時にnullと比較するのではなく、どちらかがnullなら例外になる条件にします。
- map.get(key)は値を取得するだけです。削除処理では、対応付けも消すmap.remove(key)を使います。
- reverseMapのリストが空になったときは、リスト内のキーだけでなく、値とリストの対応付けも削除します。
- tryの中で例外が発生すると、その後に書かれた処理は続行されません。このため、例外の後にあるFE0004の登録は行われません。
FAQ
Q: 同じ点数のキーは、どのような順に表示されますか?
A: reverseMapでは、同じ値に対応するキーをリストに追加します。このプログラムではリストに追加された順に取り出すため、同じ点数のキーは追加順に表示されます。
A: reverseMapでは、同じ値に対応するキーをリストに追加します。このプログラムではリストに追加された順に取り出すため、同じ点数のキーは追加順に表示されます。
Q: FE0001を85点で登録し直したとき、元の位置に残らないのはなぜですか?
A: putは、登録済みのキーをいったんremoveで削除してから、新しい値で登録し直します。そのため、85点のリストには、再登録時の順番で追加されます。
A: putは、登録済みのキーをいったんremoveで削除してから、新しい値で登録し直します。そのため、85点のリストには、再登録時の順番で追加されます。
Q: FE0004の最後の表示がnullなのはなぜですか?
A: FE0004は先に削除されています。その後の再登録は、直前のNullPointerExceptionによって実行されません。したがって、FE0004に対応する値はなく、getの結果はnullです。
A: FE0004は先に削除されています。その後の再登録は、直前のNullPointerExceptionによって実行されません。したがって、FE0004に対応する値はなく、getの結果はnullです。
関連キーワード: ジェネリクス、コンパレータ、TreeMap、HashMap、反復子、例外処理
設問2:
問題文を見る 点数が同じ場合には、学籍番号の文字列としての自然順序付けに従って出力するように変更する。クラスValueSortedMapで使用しているクラスやインタフェースの変更だけで実現する場合、変更内容として適切なものを、解答群の中から選べ。
解答群
ア:ArrayListをTreeSetに変更する。
イ:ListとArrayListをSetに変更する。
ウ:ListをSetに変更し、ArrayListをTreeSetに変更する。
エ:ListをTreeSetに変更し、ArrayListをSetに変更する。
オ:ListをTreeSetに変更する。
模範解答
ウ
解説
解答の導き方
この問題では、点数が同じ人どうしを、学籍番号の文字列としての自然順序付けで並べる方法を考えます。
まず、ValueSortedMapでは、点数と学籍番号をどのように管理しているかを確認します。点数と学籍番号の組合せはmapに保存され、reverseMapには「点数ごとに、その点数を取った学籍番号の集まり」が保存されます。
点数ごとの順番は、reverseMapを作るときに指定されたコンパレータ(並べ替えの規則)で決まります。プログラム1では点数の大きい順になるように指定されています。この順番は、同じ点数の学籍番号の並べ方とは別のものです。
一方、同じ点数に属する学籍番号は、現在、ListとArrayListで管理されています。Listは順番に要素を並べておくための型で、ArrayListはその具体的な実装です。要素は追加された順に並ぶため、学籍番号の自然順序付けになるとは限りません。
実際に、FE0003が点数85の集まりに追加された後、FE0001の点数が85に変更されています。putは同じキーが既に登録されている場合、古い対応を取り除いてから新しい値に登録するため、点数85の集まりにはFE0003、FE0001の順に追加されます。現在のListでは、この追加順のまま出力されます。
学籍番号を自然順序付けで並べるには、同じ点数の学籍番号をTreeSetで管理します。TreeSetは、要素を自然順序付けに従って保持する集合です。Stringの場合、文字列の先頭から文字を比べる順序になります。そのため、点数85の学籍番号はFE0001、FE0003の順になります。
ただし、TreeSetはListではありません。そのため、変数やフィールドの型として使っているListも、TreeSetを扱えるSetに変更する必要があります。Setは集合を扱うインタフェース(利用できる操作を定めた型)で、TreeSetはその実装クラス(実際の処理を行うクラス)です。
つまり、ListをSetに変更し、ArrayListをTreeSetに変更すれば、同じ点数の学籍番号だけを自然順序付けにできます。したがって、該当する選択肢はウです。点数ごとの順序はそのままなので、点数の高い順という条件も変わりません。
誤りやすいポイント
- Setに変更するだけでは、自然順序付けになるとは限りません。Setは重複を避けるための型であり、順序を決める役割はTreeSetが担います。
- ArrayListだけをTreeSetに変更すると、List型の変数やフィールドにTreeSetを代入できません。ListをSetに変更する必要があります。
- 点数の並び順と、同じ点数の中での学籍番号の並び順を混同しないようにします。点数の順序はreverseMapのコンパレータで決まり、学籍番号の順序は点数ごとの集まりの種類で決まります。
FAQ
Q: Setにすると、同じ学籍番号が登録されることはありませんか?
A: 同じ点数の集まりに同じ学籍番号が重複して入るのを防げます。また、putでは登録済みのキーを先にremoveしてから新しい点数に登録するため、点数変更後に古い点数の集まりにも残り続けることはありません。
A: 同じ点数の集まりに同じ学籍番号が重複して入るのを防げます。また、putでは登録済みのキーを先にremoveしてから新しい点数に登録するため、点数変更後に古い点数の集まりにも残り続けることはありません。
Q: TreeSetでいう自然順序付けとは何ですか?
A: 要素の型に用意されている標準的な並び順です。Stringの場合は、文字列を先頭から比べて並べます。
A: 要素の型に用意されている標準的な並び順です。Stringの場合は、文字列を先頭から比べて並べます。
Q: TreeSetに変更すると、点数の高い順も変わりますか?
A: 変わりません。TreeSetにするのは同じ点数に属する学籍番号の集まりです。点数どうしの順番は、reverseMapに指定されたコンパレータが決めます。
A: 変わりません。TreeSetにするのは同じ点数に属する学籍番号の集まりです。点数どうしの順番は、reverseMapに指定されたコンパレータが決めます。
関連キーワード: コレクション、Set、TreeSet、自然順序付け、コンパレータ



