基本情報技術者 2014年 春期 午後 問11
次のJavaプログラムの説明及びプログラムを読んで、設問1,2に答えよ。
〔プログラムの説明〕
雑誌記事のオンライン購読サイトをモデルとしたプログラムである。記事には、無料記事と有料記事がある。サイトの利用者は、誰でも無料記事を閲覧できる。利用者は、名前を登録することで登録会員となり、無料記事に加え、有料記事を1日に1本だけ無料で閲覧できる。登録は無料である。登録会員は、購読料を支払うことで有料会員となり、全ての記事を無制限に閲覧できる。
このプログラムは、次のクラスから成る。
(1) クラスArticle:記事を表す。
各記事には、記事識別子(id)が割り当てられる。各記事は、見出し(headline)、本文(body)及び無料記事を表すフラグ(free)から成る。記事識別子と記事は、1対1に対応し、同一記事に対してArticleのインスタンスは高々1個しか存在しない。
① 静的メソッドcreate:引数で与えられた記事識別子及び記事のデータからArticleのインスタンスを生成し、登録する。記事識別子に重複はないものとする。
② 静的メソッドgetArticle:引数で与えられた記事識別子から登録されている記事であるArticleのインスタンスを返す。記事識別子に誤りはないものとする。
③ 静的メソッドgetIds:登録されている全記事の記事識別子の集合を返す。
④ メソッドisFree:無料記事であればtrueを返す。そうでなければ、falseを返す。
⑤ その他、記事のデータを返すメソッドが用意されている。
(2) 抽象クラスUser:利用者を表す。
① コンストラクタ:引数で与えられた利用者名をもつインスタンスを生成する。
② メソッドgetName:利用者名を返す。
③ 抽象メソッドtestAndMark:引数で与えられた記事が閲覧可能かどうかを調べ、閲覧可能であればtrueを返す。そうでなければ、falseを返す。メソッドがtrueを返したとき、サイトは利用者に記事を表示するものとし、必要に応じて記事が閲覧済みであることを記録する。
(3) クラスGuest:未登録の利用者(ゲスト)を表す。
① コンストラクタ:利用者名を“ゲスト”とするインスタンスを生成する。
② メソッドtestAndMark:引数で与えられた記事が無料記事であればtrueを返す。そうでなければ、falseを返す。
(4) クラスMember:登録会員を表す。
① コンストラクタ:引数で与えられた利用者名をもつインスタンスを生成する。
② メソッドtestAndMark:引数で与えられた記事が無料記事であれば、trueを返す。有料記事の場合は、今日最初の有料記事の閲覧のとき、又は今日閲覧済みの有料記事と同一であるときは、trueを返す。それら以外のときは、falseを返す。加えて、今日最初の有料記事の閲覧のときには、閲覧済みの記事として今日の日付とともに記録する。
③ メソッドtoday:今日の日付(ローカル時間)を1970年1月1日からの日数で返す。
(5) クラスPaidMember:有料会員を表す。
① コンストラクタ:引数で与えられた利用者名をもつインスタンスを生成する。
② メソッドtestAndMark:全ての記事に対してtrueを返す。
(6) クラスSubscriptionSite:上記クラスのテスト用プログラムである。メソッドmainを実行すると、図1の結果が得られる。
なお、Member及びPaidMemberのコンストラクタに与える利用者名の衝突は、ないものとする。







設問1:
問題文を見る プログラム中のに入れる正しい答えを、解答群の中から選べ。
a, dに関する解答群
ア:!article.isFree()
イ:article.isFree()
ウ:false
エ:this.article != article
オ:this.article == article
カ:this.article == null
キ:true
bに関する解答群
ア:new User(name)
イ:super()
ウ:super(name)
エ:super.name = name
オ:this()
カ:this(name)
キ:this.name = name
ク:User(name)
cに関する解答群
ア:!=
イ:<
ウ:==
エ:>
オ:instanceof
e, fに関する解答群
ア:int i = 0; i < Article.getIds().size(); i++
イ:int i = 0; i < readers.length; i++
ウ:Member reader : readers
エ:PaidMember reader : readers
オ:String id : Article.articles
カ:String id : Article.getIds()
キ:User reader : readers
模範解答
a:イ、b:ウ、c:ウ、d:キ、e:キ、f:カ
解説
解答の導き方
空欄は、ゲスト・登録会員・有料会員それぞれの閲覧ルールと、記事や利用者を順に取り出す処理に合うものを選びます。
1. a:ゲストが閲覧できる記事
問題文では、ゲストは「無料記事であればtrue」とされています。ArticleのメソッドisFreeは、無料記事ならtrueを返します。そのため、記事が無料かどうかをそのまま調べる article.isFree() が入ります。
2. b:親クラスのコンストラクタを呼び出す
コンストラクタは、インスタンスを生成するときに初期設定を行う処理です。MemberはUserを継承するクラスです。継承とは、親クラスの機能を子クラスが受け継ぐことです。Memberの利用者名はUser側に設定するので、Memberのコンストラクタから親クラスのコンストラクタを呼び出します。
その呼び出し方は super(name) です。Memberの親クラスはUserなので、Userのコンストラクタにnameを渡せます。
PaidMemberも同じ空欄を使います。PaidMemberの親クラスはMemberなので、そこで super(name) を呼び出すと、Memberのコンストラクタに利用者名が渡されます。MemberからUserへも名前が渡るため、どちらのコンストラクタにも同じ記述が入ります。
3. c:今日すでに有料記事を閲覧したかの判定
Memberの処理を、有料記事の場合に分けて考えます。
したがって、「今日すでに閲覧したか」を判定する条件は、browseDateとtodayが等しいことです。cには == が入ります。
無料記事の場合は、この判定より前にtrueを返します。そのため、無料記事を閲覧しても有料記事の閲覧記録は更新されず、1日に読める有料記事の枠を使いません。
4. d:有料会員の閲覧判定
問題文では、有料会員は「全ての記事を無制限に閲覧できる」とされています。PaidMemberのtestAndMarkは、記事の種類にかかわらずtrueを返せばよいので、dには true が入ります。
PaidMemberはMemberを継承していますが、同じ名前のメソッドを定義し直しています。これはオーバーライドといい、親クラスのメソッドの動作を子クラス用に置き換えることです。
5. eとf:利用者と記事識別子を順に取り出す
readersはUser型の配列です。配列は、複数の値を順番にまとめて扱うものです。この配列にはGuest、Member、PaidMemberのインスタンスが入っています。これらはすべてUserを継承しているため、利用者を1人ずつ取り出す変数の型はUserにします。
配列や集合などから要素を順番に取り出す書き方を拡張for文といいます。eには User reader : readers が入ります。Member readerではGuestを扱えず、PaidMember readerではGuestやMemberも扱えないため、Userを指定するのが適切です。
Article.getIds()は、記事識別子をまとめたSet<String>を返します。Setは、複数の値をひとまとまりにして扱う集合です。記事識別子はString型なので、fには String id : Article.getIds() が入ります。
処理の対象を具体的に見ると、「0001」は無料記事、「0002」は有料記事、「0003」は無料記事です。ゲストは無料記事だけを閲覧できます。登録会員は無料記事に加えて、その日に最初の有料記事を閲覧できます。有料会員は全記事を閲覧できます。これが図1の実行結果につながります。
誤りやすいポイント
- ゲストの判定を反対にしないようにします。無料記事を見られるので、isFreeの結果を反転せずに使います。
- Memberの判定は「今日と同じ日付なら、新しい有料記事も見られる」ではありません。今日すでに閲覧した記事と同じ記事だけを再度閲覧できます。
- 無料記事を閲覧しても、有料記事の閲覧記録は更新されません。
- 有料会員の判定は、Memberの制限をそのまま使うのではありません。PaidMemberがtestAndMarkをオーバーライドして、常にtrueを返します。
- readersの中にはGuestもいるため、eの変数型をMemberやPaidMemberにはできません。また、Article.getIds()から取り出すのは記事そのものではなく、String型の記事識別子です。
- Articleでは、同一記事に対してインスタンスが高々1個しか存在しません。そのため、記事が同じかどうかを browsedArticle == article で判定できます。ここでの==は、2つの変数が同じインスタンスを指しているかを調べます。
FAQ
Q: 登録会員は、今日最初に閲覧した有料記事を同じ日にもう一度見られますか?
A: 見られます。browseDateが今日と同じ場合でも、閲覧済みの記事と今回の記事が同じならtrueを返します。
A: 見られます。browseDateが今日と同じ場合でも、閲覧済みの記事と今回の記事が同じならtrueを返します。
Q: 登録会員が無料記事を先に読んだ場合、その日に読める有料記事の枠は使われますか?
A: 使われません。無料記事はtrueを返して処理を終えるため、有料記事の閲覧記録は更新されません。
A: 使われません。無料記事はtrueを返して処理を終えるため、有料記事の閲覧記録は更新されません。
Q: 有料会員のコンストラクタでsuper(name)を呼ぶと、利用者名はどこに設定されますか?
A: まずMemberのコンストラクタに渡され、MemberからUserのコンストラクタへ渡されます。最後にUserのnameに利用者名が設定されます。
A: まずMemberのコンストラクタに渡され、MemberからUserのコンストラクタへ渡されます。最後にUserのnameに利用者名が設定されます。
関連キーワード: 継承、メソッドのオーバーライド、コンストラクタ、拡張for文、配列、集合
設問2:
問題文を見る プログラム6で記事識別子"0003"の記事の無料記事を表すフラグの値をfalseにしてプログラムを実行したとき、"<閲覧不可>"は何回出力されるか、正しい答えを、解答群の中から選べ。ここで、プログラム中のa〜fには正しい答えが入っているものとし、プログラムは日をまたいで実行しないものとする。
解答群
ア:0回
イ:1回
ウ:2回
エ:3回
オ:4回
カ:5回
模範解答
エ
解説
解答の導き方
変更後のプログラムでは、記事識別子「0001」の記事は無料のままです。一方、「0002」と「0003」の記事は、どちらも有料記事になります。利用者ごとに、閲覧できない記事の数を数えます。
まず、Guestについて考えます。説明には、Guestは無料記事なら閲覧できるとあります。「0001」は無料なので閲覧できます。「0002」と「0003」は有料なので、どちらも閲覧できません。Guestでは「<閲覧不可>」が2回出力されます。
次に、Memberについて考えます。無料記事は閲覧できるため、「0001」は閲覧できます。有料記事は、今日最初の1本を閲覧できます。したがって、最初に処理される有料記事「0002」は閲覧でき、その記事が閲覧済みとして記録されます。
その後の「0003」も有料記事ですが、「0002」とは別の記事です。今日すでに有料記事を閲覧していて、閲覧済みの記事とも異なるため、閲覧できません。Memberでは「<閲覧不可>」が1回出力されます。
最後に、PaidMemberは「全ての記事に対してtrueを返す」ので、閲覧できない記事はありません。「<閲覧不可>」は0回です。
合計は 回です。よって、選ぶのはエです。
誤りやすいポイント
- Memberは有料記事を何本でも閲覧できるわけではありません。説明にあるのは、今日最初の有料記事を無料で閲覧できるという仕組みです。
- 今日すでに有料記事を閲覧していても、同じ記事なら閲覧できます。ただし、このプログラムでは「0002」と「0003」は別の記事なので、2本目は閲覧できません。
- 無料記事は有料記事の閲覧回数に含まれません。Memberは「0001」を閲覧しても、その後の有料記事の閲覧可否には影響しません。
- PaidMemberはMemberを継承していますが、testAndMarkを上書きして、全ての記事を閲覧できるようにしています。
FAQ
Q: Memberが最初に閲覧できる有料記事は、どのように決まりますか?
A: プログラムで先に処理された有料記事です。この問題では記事識別子の順に処理されるため、「0002」が最初になります。
A: プログラムで先に処理された有料記事です。この問題では記事識別子の順に処理されるため、「0002」が最初になります。
Q: 無料記事を閲覧すると、Memberの「今日最初の有料記事」の権利を使いますか?
A: 使いません。無料記事は、Memberの処理で有料記事かどうかを調べる前に閲覧可能と判定されます。
A: 使いません。無料記事は、Memberの処理で有料記事かどうかを調べる前に閲覧可能と判定されます。
Q: 同じ有料記事をもう一度読む場合はどうなりますか?
A: 今日閲覧済みの記事と同じ記事なら、Memberは閲覧できます。この問題では記事をそれぞれ1回ずつ処理するため、同じ記事を再度読む場面はありません。
A: 今日閲覧済みの記事と同じ記事なら、Memberは閲覧できます。この問題では記事をそれぞれ1回ずつ処理するため、同じ記事を再度読む場面はありません。
関連キーワード: 継承、抽象クラス、メソッドのオーバーライド、条件分岐、コレクション



