基本情報技術者 2011年 秋期 午後 問11
次のJavaプログラムの説明及びプログラムを読んで、設問1,2に答えよ。
〔プログラムの説明〕
名前及び住所からなる住所録のエントリの追加、削除及び検索を行う住所録管理プログラムであり、次のクラスからなる。
(1) クラスNameは、姓及び名をそれぞれ文字列で保持する。
(2) クラスAddressは、郵便番号及び住所を保持する。郵便番号は、上位3桁と下位4桁をそれぞれint型の整数で保持する。住所は、文字列で保持する。
(3) クラスAddressBookは、住所録である。入れ子クラスAddressBook.Entryは、住所録のエントリであり、NameとAddressのインスタンスを保持する。クラスAddressBookは、エントリを追加及び削除するメソッドをもつ。
クラスName, Address, 及びAddressBook.Entryのインスタンスは、検索可能である。検索処理を支援するために、次のインタフェースを定義する。
(1) インタフェースSearchCriteriaは、検索条件を示すデータ型であり、メソッドをもたない。
(2) インタフェースSearchableは、これを実装するクラスが検索条件を与えて検索可能であることを示す。検索するときは、メソッドmeetsを呼び出す。
クラスName及びAddressは、それぞれ入れ子クラスCriteriaを定義し、そのCriteriaを検索条件とするインタフェースSearchableを実装する。
(1) 入れ子クラスName.Criteriaは、引数familyName及びgivenNameでそれぞれ姓及び名を検索条件として指定する。検索条件に含めないときは、nullを指定する。
(2) クラスNameは、インタフェースSearchableを実装する。メソッドmeetsは、引数で与えられたcriteriaで実装されたメソッドを呼び出し、このクラスのインスタンスが検索条件に合致するかどうか調べる。
(3) 入れ子クラスAddress.Criteriaは、引数postalCode3, postalCode4及びaddrでそれぞれ郵便番号の上位3桁、下位4桁及び住所を検索条件として指定する。検索条件に含めないときは、postalCode3及びpostalCode4は負の値、addrはnullを指定する。住所については、部分文字列が一致する場合も合致しているとみなす。例えば、“京都”は“東京都”の部分文字列なので、合致するとみなす。
(4) クラスAddressは、インタフェースSearchableを実装する。メソッドmeetsは、引数で与えられたcriteriaで実装されたメソッドを呼び出し、このクラスのインスタンスが検索条件に合致するかどうか調べる。
クラスAddressBookのメソッドmeetsAnyOfは、引数で与えられたインタフェースSearchCriteriaのどれかに合致するエントリの集合を返す。メソッドmeetsAllOfは、引数で与えられたSearchCriteriaの全てに合致するエントリの集合を返す。
入れ子クラスAddressBook.Entryは、インタフェースSearchableを実装する。メソッドmeetsは、引数で与えられたSearchCriteriaの具体的な型によって、name又はaddrのメソッドmeetsを呼び出し、このAddressBook.Entryのインスタンスが引数で指定された検索条件に合致するかどうか調べる。
なお、クラスName, Address, AddressBook.Entryは、インタフェースSetで使用できるように、クラスObjectのメソッドequals及びhashCodeを上書きしているものとする。また、各コンストラクタ及びメソッドの引数は正しいものとする。
クラスTestは、この住所録プログラムのテストプログラムである。メソッドmainを実行すると、次の結果が得られた。







設問1:
問題文を見る プログラム中のに入れる正しい答えを、解答群の中から選べ。
aに関する解答群
ア:SearchCriteria
イ:SearchCriteria<Name>
ウ:SearchCriteria<String>
エ:Searchable
オ:Searchable<Name>
カ:Searchable<String>
b, cに関する解答群
ア:book.add(entry)
イ:book.add(sc)
ウ:book.remove(entry)
エ:book.remove(sc)
オ:result.add(entry)
カ:result.add(sc)
キ:result.remove(entry)
ク:result.remove(sc)
d, eに関する解答群
ア:Address.Criteria
イ:Criteria
ウ:Entry.Criteria
エ:Name.Criteria
オ:SearchCriteria
模範解答
a:ア、b:オ、c:キ、d:オ、e:ア
解説
解答の導き方
この問題では、検索条件を表す型と、検索結果を集める処理を順に確認します。
-
a:Name.Criteriaが実装する型を考えます問題文では、SearchCriteriaを「検索条件を示すデータ型」と説明しています。また、Name.Criteriaは姓や名を検索条件として持つクラスです。Searchableの定義は、検索条件の型を指定するジェネリクス(扱う型を指定する仕組み)を使っており、指定する型にはSearchCriteriaを実装している必要があります。Name.Criteriaは検索条件なので、実装するのはSearchCriteriaです。したがって、aにはSearchCriteriaが入ります。SearchCriteria自体は型を受け取る定義ではないため、SearchCriteria<Name>のようには書きません。
-
b:一致したエントリの追加先を考えますmeetsAnyOfは、名前または住所のどれかの検索条件に合うエントリを集めます。処理では、各検索条件と住所録の各エントリを調べ、一致したときに結果を追加します。住所録そのものではなく、結果を格納するresultにEntryを追加する必要があります。したがって、bにはresult.add(entry)が入ります。この処理で使われているSetは、同じ要素を重複して持たない集合です。そのため、同じエントリが複数の検索条件に一致しても、結果には重複して入りません。
-
c:全ての条件に合わないエントリの扱いを考えますmeetsAllOfは、最初に住所録の全エントリをresultにコピーしています。その後、各エントリについて検索条件を調べ、条件に一つでも一致しなければ結果から除きます。つまり、削除先は住所録bookではなく、絞り込み途中のresultです。また、削除するのは条件を示すSearchCriteriaではなく、条件に合わなかったEntryです。したがって、cにはresult.remove(entry)が入ります。
-
d:Entryのmeetsが受け取る型を考えますEntryはSearchable<SearchCriteria>を実装しています。Searchableのmeetsは、指定した型の検索条件を受け取るメソッドです。そのため、Entryのmeetsの引数もSearchCriteriaになります。ここでName.Criteriaだけを指定すると、住所の検索条件であるAddress.Criteriaを受け取れません。dにはSearchCriteriaが入ります。
-
e:住所の検索条件の型を考えますEntryのmeetsは、受け取った検索条件の具体的な型を調べます。Name.Criteriaならnameのmeetsを呼び出し、住所の検索条件ならaddrのmeetsを呼び出します。住所の検索条件を表すクラスはAddress.Criteriaです。そのため、型の確認にはAddress.Criteriaを使い、住所の検索条件として扱うときも同じ型に変換します。したがって、eにはAddress.Criteriaが入ります。
-
検索結果がどうなるかを確認しますテストプログラムでは、名前の条件が「名が太郎」で、住所の条件が「住所に青葉区を含む」です。住所の条件で郵便番号に負の値を指定しているため、郵便番号は検索に使われません。住所は部分文字列が一致すればよいので、「横浜市青葉区」や「仙台市青葉区」は条件に合います。meetsAnyOfは「どれか一つ」に一致すればよいので、3件が結果に含まれます。meetsAllOfは「全て」に一致する必要があるので、両方の条件に合う1件だけが含まれます。図1の実行結果も、この件数になっています。
誤りやすいポイント
-
bでbookに追加しないこと
bookは住所録そのものです。検索結果を作る処理なので、一致したエントリはresultに追加します。 -
cで検索条件を削除しないこと
削除する対象は、検索条件ではなく、一つ以上の条件に一致しなかったEntryです。 -
「どれか」と「全て」を取り違えないこと
meetsAnyOfは検索条件のどれかに一致すれば結果に加えます。meetsAllOfは、全ての条件に一致しないエントリを結果から取り除きます。 -
住所の部分一致を見落とさないこと
問題文では住所について部分文字列が一致すれば合致するとしています。「青葉区」を含む住所は、住所検索の条件に合います。 -
HashSetの表示順を決まった順番だと思わないこと
HashSetは要素の並び順を保証しません。図1と表示順が違っていても、含まれているエントリが同じなら検索結果としては同じです。
FAQ
Q: 検索条件をSearchCriteriaでまとめるのはなぜですか?
A: 名前の条件と住所の条件を、共通の型としてまとめて扱うためです。Entryは受け取った条件の種類を確認し、対応するNameまたはAddressの検索処理につなぎます。
A: 名前の条件と住所の条件を、共通の型としてまとめて扱うためです。Entryは受け取った条件の種類を確認し、対応するNameまたはAddressの検索処理につなぎます。
Q: meetsAllOfでは、条件に合わないと分かった後にbreakするのはなぜですか?
A: 一つでも条件に合わなければ、そのエントリは「全ての条件に一致する」という要件を満たしません。残りの条件を調べても結果は変わらないため、そのエントリの確認をそこで終えます。
A: 一つでも条件に合わなければ、そのエントリは「全ての条件に一致する」という要件を満たしません。残りの条件を調べても結果は変わらないため、そのエントリの確認をそこで終えます。
Q: meetsAnyOfの結果に、同じエントリが複数回追加されることはありませんか?
A: 同じエントリが複数の条件に一致することはありますが、結果はSetなので重複して保持されません。
A: 同じエントリが複数の条件に一致することはありますが、結果はSetなので重複して保持されません。
関連キーワード: インタフェース、ジェネリクス、可変長引数、集合、部分文字列検索
設問2:
問題文を見る クラスTestにおいて、住所録addrbookに登録されている全エントリを取得する方法として正しい答えを、解答群の中から二つ選べ。ここで、プログラム中のには、正しい答えが入っているものとする。
解答群
ア:addrbook.meetsAllOf(new Name.Criteria("", ""))
イ:addrbook.meetsAllOf(new Name.Criteria(null, null))
ウ:addrbook.meetsAllOf(null)
エ:addrbook.meetsAnyOf(new Name.Criteria("", ""))
オ:addrbook.meetsAnyOf(new Name.Criteria(null, null))
カ:addrbook.meetsAnyOf(null)
模範解答
イ、オ
解説
解答の導き方
-
検索条件に指定しない項目は、条件に合うかどうかを判定しません。問題文には、Name.Criteriaの姓と名について「検索条件に含めないときは、nullを指定する」とあります。Name.Criteriaの処理では、姓がnullなら姓の比較を通過し、名がnullなら名の比較も通過します。二つの判定はどちらも満たす必要がありますが、両方をnullにすれば、名前にかかわらず判定を通過します。したがって、Name.Criteriaの引数を姓も名もnullにすれば、住所録のどのエントリもこの検索条件に合います。
-
meetsAllOfでは、全エントリを残せます。meetsAllOfは、最初に住所録の全エントリを検索結果に入れます。その後、検索条件に合わないエントリを結果から取り除きます。今回はName.Criteriaの検索条件に全エントリが合うため、どのエントリも取り除かれません。よって、イの呼出しで全エントリを取得できます。
-
meetsAnyOfでも、全エントリを検索結果に入れられます。meetsAnyOfは、最初は空の検索結果を用意し、検索条件のどれかに合うエントリを追加します。今回のName.Criteriaには全エントリが合うため、全エントリが追加されます。よって、オの呼出しでも全エントリを取得できます。
-
ほかの選択肢は、条件の指定方法が異なります。アとエでは、姓と名に空文字列を指定しています。nullとは違い、空文字列は「条件を指定しない」という意味ではありません。実際の名前と空文字列が一致するかを調べます。テストプログラムで登録している姓と名は空文字列ではないため、全エントリを取得できません。ウとカのnullは、Name.Criteriaの中に指定するnullとは意味が異なります。meetsAllOfやmeetsAnyOfの引数は可変長引数(複数の値をまとめて受け取れる引数)です。この位置にnullを一つだけ書くと、検索条件の配列そのものがnullとして渡されます。その配列を繰り返し処理しようとしてエラーになるため、正しい方法ではありません。
誤りやすいポイント
- Name.Criteriaの引数に指定するnullと、meetsAllOfやmeetsAnyOfに渡すnullを混同しないようにします。前者は「その項目を条件にしない」という意味ですが、後者は検索条件の配列そのものがnullになります。
- 空文字列とnullは同じではありません。空文字列は「空の文字列と一致するか」を調べる値です。
- meetsAllOfは「すべての条件に合うもの」、meetsAnyOfは「どれかの条件に合うもの」を検索します。今回はどちらも、全エントリに合う検索条件を一つ指定しているため、全エントリが結果に残ります。
FAQ
Q: Name.Criteriaの姓と名を両方nullにすると、なぜ全エントリが合うのですか?
A: Nameの検索処理では、条件がnullなら、その項目の比較を行わずに合格とします。姓と名の両方がnullなので、名前による絞り込みが行われません。
A: Nameの検索処理では、条件がnullなら、その項目の比較を行わずに合格とします。姓と名の両方がnullなので、名前による絞り込みが行われません。
Q: 検索条件を何も指定しないために、meetsAllOf(null)と書くのではないのですか?
A: このメソッドでは、引数にnullを渡すと「検索条件がない」のではなく、「検索条件の配列がnull」と扱われます。全エントリに合う条件を渡すには、Name.Criteria(null, null)のように検索条件の中身を指定します。
A: このメソッドでは、引数にnullを渡すと「検索条件がない」のではなく、「検索条件の配列がnull」と扱われます。全エントリに合う条件を渡すには、Name.Criteria(null, null)のように検索条件の中身を指定します。
Q: meetsAllOfとmeetsAnyOfのどちらを使ってもよいのはなぜですか?
A: 今回は検索条件が一つで、その一つが全エントリに合います。そのため、「すべての条件」でも「どれかの条件」でも、結果は住所録の全エントリになります。
A: 今回は検索条件が一つで、その一つが全エントリに合います。そのため、「すべての条件」でも「どれかの条件」でも、結果は住所録の全エントリになります。
関連キーワード: 検索条件、論理積、論理和、可変長引数、集合



