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

午前試験免除制度対応!基本情報技術者試験のeラーニング【独習ゼミ】

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

次のJavaプログラムの説明及びプログラムを読んで,設問1,2に答えよ。

〔プログラムの説明〕
 電気料金プラン(以下,プランという)を比較するためのプログラムである。電気料金は,基本料金,及び電気の使用量(以下,電力量という)から算出される電力量料金から成る。電力量の単位は,キロワット時(kWh)である。電力量料金を算出するための1kWh当たりの料金(以下,料金単価という)は,電力量に応じて段階的に変わる。プランA及びプランBの料金表を表1に示す。
pm11_1.gif
 例えば,プランAで,使用した電力量が200.5kWhのとき,120kWh分に対して19.62円/kWh,残りの80.5kWhに対して26.10円/kWhの料金単価が適用される。
  • 抽象クラス TierTable は,段階的に変化する値のペアをテーブルとして表現する。値は,型doubleで与えられる。
    1. コンストラクタは,可変長の引数で与えられたdoubleの数値2個ずつをペアとして配列にし,更にその配列を要素とする配列を生成し,フィールド pairs に保持する。引数 tiers の長さが奇数のときは,IllegalArgumentException を投げる。
    2. 抽象メソッド map は,引数で与えられた数値を別の数値に変換して返す。
  • クラス TieredRateTable は,料金単価のテーブルを表す。
    1. コンストラクタは,引数で与えられた電力量とそれに対応する料金単価のペアからテーブルを作成する。
    2. メソッド map は,引数で与えられた電力量から電力量料金を計算し,その値を返す。
  • クラス RatePlan は,プランを表す。
    1. コンストラクタは,引数で与えられたプラン名,基本料金,料金単価のテーブルで表されるインスタンスを生成する。
    2. メソッド getName は,プラン名を返す。
    3. メソッド getPrice は,引数で与えられた電力量から電力量料金を計算し,その値と基本料金の合計を型intの数値で返す。このとき,小数点以下は切り捨てられる。
  • クラス Main は,表1を基にプランA及びプランBを表す RatePlan のインスタンスを生成し,電力量が543.0kWhのときの電気料金を比較する。メソッド main を実行すると,図1の結果が得られた。
pm11_2.gif
pm11_3.gif

設問1

プログラム中の に入れる正しい答えを,解答群の中から選べ。
a に関する解答群
  • abstract
  • final
  • private
  • protected
  • public
  • static
b に関する解答群
  • i
  • i - 1
  • i * 2
  • i / 2
  • i / 2 + 1
  • i + 1
c,d に関する解答群
  • [i + 1][0]
  • [i + 1][1]
  • [i + 1][i]
  • [i][0]
  • [i][1]
  • [i][i + 1]
解答選択欄
  • a:
  • b:
  • c:
  • d:
  • a=
  • b=
  • c=
  • d=

解説

aについて〕
〔プログラムの説明〕(1)に「抽象クラス TierTable」と説明されています。抽象クラスとは、抽象メソッドを1つ以上含むクラスでそれ自体をインスタンス化することはできず、必ずサブクラスに継承して使います。抽象クラスを定義するときには、class の前に修飾子「abstract」を付けなければなりません。よって、[a]には「abstract」が入ります。

a=ア:abstract
  • 正しい。abstractは、抽象クラスを表す修飾子です。
  • final を付けたクラスは継承不可となります。抽象クラスを表す修飾子ではないので誤りです。
  • private は、クラスの可視範囲を指定するアクセス修飾子ですので誤りです(インナークラスのみで使用可)。
  • protected は、クラスの可視範囲を指定するアクセス修飾子ですので誤りです(インナークラスのみで使用可)。
  • public は、クラスの可視範囲を指定するアクセス修飾子ですので誤りです。
  • static を付けたクラスは、クラス内に静的メンバーしか定義できず、インスタンスを生成できない静的クラスになります。
bについて〕
〔プログラムの説明〕(1)に「コンストラクタは,可変長の引数で与えられたdoubleの数値2個ずつをペアとして配列にし,更にその配列を要素とする配列を生成し,フィールド pairs に保持する。」と説明されています。〔プログラム4〕のMain内で示されているように、クラス TierTable のコンストラクタでは、実数型の数値を複数受け取ります。引数 tiers は、doubleの数値が格納されている配列であり、これを2個ずつペアにするのですから、2次元配列 a の要素数は、引数 tiers の要素数の半分、すなわち「tiers.lengths / 2」となります。

[b]直前のforループの条件式を見ると、増分処理が「i += 2」となっていて i は2ずつ増えていくことがわかります。i は0から始まり、2→4→6→…と増えていくので、続く[b]の式で2次元配列 a の要素(a[0]→a[1]→a[2]→…)を先頭から漏れなく埋めていくためには、a の添字として i を2で割った商を使うのが適切です。

b=エ:i / 2

引数 tiers と2次元配列 a の関係は次のようになります。
pm11_7.gif
cdについて〕
map は引数に与えられる電力量 amount から電力量料金を計算するメソッドです。メンバー変数 pairs には、上記の2次元配列形式で電力量範囲の下限と料金単価が以下のように格納されているので、これを基準に電力量料金を計算することになります。
pm11_8.gif
具体例として、〔プログラムの説明〕に挙げられているのと同じく、電力量を表す引数 amount が 200.5 のときを考えてみます。このケースでは〔プログラムの説明〕にあるように、120kWhまでに対して19.62円を適用し、残りの「200.5ー120=80.5kWh」に対して26.10円を適用することになっています。

[c][d]を含むforループは2回行われ、上表のα→βの順に各区分の料金を計算しています(amountが300未満なのでγ部分は行われません)。
1回目(i=0)
if文の条件式が「0+1 < 3 && 200.5 > 120」と真となるので、if文内の処理が実行されます。
2回目(i=1)
if文の条件式が「1+1 < 3 && 200.5 > 300」が偽となるので、else文の処理が実行されます。
[c][d]を含む処理は、引数の電力量が1つ上の区分の下限値(本ケースでは120)を超えている場合に行われる処理です。この場合、200.5kWhのうち120kWh分に安い単価を適用するために、[現在の区分の単価が適用される電力量] × [料金単価] を料金(charge)に加算する必要があります。

pairs の内容を見るとわかるように、α区分の対象となる電力量は「pairs[1][0] - pairs[0][0]」、β区分の対象となる電力量は「pairs[2][0] - pairs[1][0]」というように、1つ上の区分の下限値から現在の区分の下限値を減算することで求められます。これを i を使って表すと、「pairs[i+1][0] - pairs[i][0]」となります。

c=ア:[i + 1][0]
 d=エ:[i][0]

なお、現在の区分が料金表の最終区分のとき、または、電力量が1つ上の区分の下限値以下となったときはelse文内で計算された料金が charge に加算されます。

設問2

割引プランは,指定した他のサービスを電気と一緒に利用した場合には,プランAやプランBという当初のプランで計算した電気料金を,電気料金の額に応じて割り引くプランである。割引プランの割引率の例を,表2に示す。
pm11_4.gif
 プログラム5は,割引率を求めるためのクラス DiscountTable である。メソッド map は,引数で与えられた電気料金から割引率を求め,その値を返す。ここで,割引率は小数で与えるものとする。例えば,1%は0.01である。
pm11_5.gif
 プログラム6は,割引プランを表すためのクラス DiscountPlan である。 DiscountPlan は,クラス RatePlan を拡張し,上位クラスである RatePlan のメソッド getPrice で求めた電気料金から割引率を求め,割引を適用した金額を電気料金として計算する。プログラム中の に入れる正しい答えを,解答群の中から選べ。
pm11_6.gif
e に関する解答群
  • extends
  • implements
  • imports
  • public
  • throws
f に関する解答群
  • ((RatePlan) this)
  • RatePlan
  • super
  • this
  • TieredRateTable
  • TierTable
g に関する解答群
  • (1.0 - discountTiers.map(amount))
  • (1.0 - discountTiers.map(basicCharge))
  • (1.0 - discountTiers.map(price))
  • discountTiers.map(amount)
  • discountTiers.map(basicCharge)
  • discountTiers.map(price)
解答選択欄
  • e:
  • f:
  • g:
  • e=
  • f=
  • g=

解説

eについて〕
〔プログラム6〕に関する説明に「DiscountPlan は,クラス RatePlan を拡張し」とあります。Javaで既存クラスを拡張したクラスを定義するときには、以下の書式で記述します。
class [子クラス名] extends [親クラス名]

e=ア:extends
  • 正しい。extends は子クラス(サブクラス)を定義するときに使う予約語です。
  • implements はインタフェースを実装するときに付ける予約語なので不適切です。
  • imports は存在しない予約語なので不適切です。なお、「import」はパッケージをクラスに読み込む際に使用します。
  • public はクラス名の前に付けるアクセス修飾子なので不適切です。
  • throws は、例外名の前につける予約語なので不適切です。
fについて〕
設問2の〔プログラム6〕に関する説明に「上位クラスである RatePlan のメソッド getPrice で求めた電気料金から割引率を求め…」とあります。子クラスから親クラスのフィールドやメソッドを使用する際には「super」を使います。他の選択肢はすべて、上位クラスのメソッドを呼び出すときに用いることができず不適切です。

f=ウ:super

gについて〕
[g]を含む部分は、割引を適用した電気料金を求める処理を行っています。1つ前の行で、price に割引適用前の電気料金を格納しているので、これに[g]を掛けて割引適用後の金額にすればよいわけです。

プログラム5の説明にあるように、クラス DiscountTable のメソッド map は「引数で与えられた電気料金から割引率を求め,その値(小数)を返す。」ので、[g]は、DiscountTable の map の返り値を使って「1 - 割引率」とすればよいです。メソッド map の引数は電気料金ですから、price を指定するのが適切です。

g=ウ:(1.0 - discountTiers.map(price))

他の選択肢についてですが、map は割引率を求めるメソッドなので「エ」「オ」「カ」は除外できます。「ア」「イ」「ウ」の違いは map に渡す引数です。参考までに、この引数が〔プログラム6〕中で何を表しているか確認してみます。
  • amount:電力量
  • basicCharge:基本料金
  • price:電気料金
amount は電力量を、basicCharge は基本料金を保持する変数なので不適切です。なお、amount という変数名は〔プログラム6〕中では電力量を表していますが、〔プログラム5〕中では電気料金を表しているので注意が必要です。元が〔プログラム1〕の抽象メソッド内の変数なので、電力量や電気料金という具体的な量ではなく、「何かの」量を表せるように汎用的に命名していると考えるとよいでしょう。

Pagetop