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

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

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

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

〔プログラムの説明〕
 A君は,先輩エンジニアであるBさんの指導の下で,表現式(以下,式という)を構築するためのライブラリの作成を進めている。ライブラリはAPIを提供する。まず,次のインタフェース及びクラスをパッケージ com.example.expr に作成した。
  • インタフェース Expression は,式を表す。すなわち,Expression を実装するクラスは,型としての式を表す。
    1. メソッド evaluate は,式を評価した結果を型 int で返す。
  • クラス Constant は,定数を式(型 Expression )として表す。
    1. コンストラクタは,引数で与えられた型 int の値を表す定数を生成する。
    2. メソッド evaluate は,この定数の値を返す。
    3. メソッド toString は,この定数の値を文字列として返す。
  • クラス Addition は,加算を式(型 Expression )として表す。
    1. コンストラクタは,加算式を生成する。加算式 a+b において,演算子+の左側 a の部分を左側の式,右側 b の部分を右側の式とし,それぞれ引数 left 及び引数 right で指定する。いずれかの引数が null のときは,NullPointerException を投げる。
    2. メソッド evaluate は,左側の式を評価した値に右側の式を評価した値を加え,その値を返す。
    3. メソッド toString は,この加算式を表す文字列を返す。
pm11_1.png

設問1

A君は,クラス Constant 及び Addition をAPIとして呼び出すテストをするために,クラス Test をパッケージ com.example.test に作成して実行したところ,図1の出力結果を得た。プログラム4中の に入れる正しい答えを,解答群の中から選べ。
pm11_2.png
pm11_3.png
a に関する解答群
  • com.example.expr
  • com.example.test
  • static com.example.expr
  • static com.example.test
b に関する解答群
  • 2,5
  • 5,2
  • five
  • five,two
  • two
  • two,five
c,d に関する解答群
  • add
  • add.evaluate()
  • five
  • five.evaluate()
  • two
  • two + five
  • two.evaluate()
解答選択欄
  • a:
  • b:
  • c:
  • d:
  • a=
  • b=
  • c=
  • d=

解説

aについて〕
問題文より、プログラム1~4のパッケージは下記となります。
pm11_7.png
import文は、他パッケージのクラスやインタフェースを参照するための文です。そのため、Test クラスからプログラム1~3のクラスを参照するには、
import com.example.expr.Addition;
import com.example.expr.Constant;
import com.example.expr.Expression;
上記宣言が必要となります。よって、解答は「ア」です。

a=ア:com.example.expr

bについて〕
問題文〔プログラム3〕より、Addition クラスのコンストラクタを確認します。
public Addition(Expression left, Expression right) {
  if (left == null || right == null) {
    throw new NullPointerException();
  }
  this.left = left;
  this.right = right;
}
Expression型の引数を2個、受け取る実装です。

この時点で、
  • 「ア」「イ」…プリミティブ型(int型)
  • 「ウ」「オ」…引数が1つ
のため除外されます。

続いて、問題文の図1「メソッドmainの出力結果」を確認します。
(2 + 5) = 7
この後のcにも関わりますが、Addition クラスの toString メソッドを確認すると、
public String toString() {
  return String.format("(%s + %s)", left, right);
}
left、rightの順で、( )で囲んだ文字列として返すメソッドです。よって、解答は「カ」です。

「エ」の場合、(5 + 2) = 7 と表示されるため不正解です。なお、String.format メソッドの引数として left、right をそのまま渡していますが、内部では left と right の toString メソッドが呼び出されています。

b=カ:two,five

cについて〕
図1「メソッドmainの出力結果」の通り、"(2 + 5)"と表示するコードです。Addition クラスの toString メソッドが正解なので add.toString() としたいですが、選択肢にはありません。

Javaの言語仕様上、System.out.println() の引数にオブジェクトを渡すと、内部ではそのオブジェクトの toString() メソッドが呼び出されます。このため、add オブジェクトのみでも同様の動作となり、整形式が出力されます。よって、解答は「ア」です。

詳しく知りたい場合はJava APIドキュメントを参照してください。
クラスPrintStream out
https://docs.oracle.com/javase/jp/8/docs/api/java/lang/System.html#out
クラスPrintStream println
https://docs.oracle.com/javase/jp/8/docs/api/java/io/PrintStream.html#println-java.lang.Object-
クラスString valueOf
https://docs.oracle.com/javase/jp/8/docs/api/java/lang/String.html#valueOf-java.lang.Object-

c=ア:add

dについて〕
問題文の「図1 メソッドmainの出力結果」の通り、"7"と表示するコードです。
  • cで解説した通り、"(2 + 5)"と表示されます。
  • 正しい。"7"と表示されます。※toString()メソッドが省略されています。
  • "5"と表示されます。
  • "5"と表示されます。
  • "2"と表示されます。
  • "25"と表示されます。two と five の加算のように見えますが、文字列結合のため"7"にはなりません。
    7と表示したい場合は、
    (two.evaluate() + five.evaluate())
    と記述する必要があります。なお、外側の ( ) が無い場合、文字列結合となります。
  • "2"と表示されます。
d=イ:add.evaluate()

設問2

次の記述中の に入れる正しい答えを,解答群の中から選べ。

 A君は,これまでに作成したプログラムをBさんに見てもらったところ,次のアドバイスを受けた。
 "乗除算などの式を実装するクラスを追加する前に,上位クラスを導入してニ項演算を表すクラスを簡単に実装できるようにすべきである。また,アプリケーションが必要とする全てのニ項演算をライブラリで用意するのは一般に難しいので,パッケージ外でも二項演算がそのクラスの下位クラスとして簡単に実装できるようにすべきである。"
 そこで,A君は,次の仕様の抽象クラスをライブラリに追加した。
  1. 抽象クラス BinaryOperatorExpression は,二項演算子を使用する式(以下,二項演算式という)を表す。
    1. コンストラクタは,二項演算式を生成する。二項演算式 a OP b において,ニ項演算子 OP の左側 a の部分を左側の式,右側 b の部分を右側の式とし,それぞれ引数 left 及び引数 right で指定する。いずれかの引数がnullのときは,NullPointerExceptionを投げる。
    2. メソッド getLeft 及び getRight は,それぞれ左側の式及び右側の式を返す。
    3. 抽象メソッド getOperator は,この二項演算式の演算子を文字列で返す。
    4. メソッド toString は,この二項演算式を表す文字列を返す。
 このクラスをBさんに見てもらったところ,"ライブラリで用意されたAPIを呼び出すアプリケーションで二項演算式を表すクラスの実装に使えるようにすることが目的なので, ようにするために,コンストラクタとメソッド getLeft,getRight 及び getOperator は public ではなく protected にすべきである"という指摘を受け,その修正をしてプログラム5を作成した。
pm11_4.png
解答群
  • 下位クラスを実装するクラスだけで使える
  • 上位クラスの実装が下位クラスで改変されない
  • 通常のアプリケーションがどのパッケージからでも呼び出せる
  • パッケージ com.example.expr 内の下位クラスだけで使える
解答選択欄
  •  
  •  

解説

アクセス修飾子に関する問題で、解答群はそれぞれのアクセス修飾子を意味しています。
  • protected
  • private
  • public
  • 無し
設問2の問題文中に

「パッケージ外でも二項演算がそのクラスの下位クラスとして簡単に実装できるようにすべきである」
「ライブラリで用意されたAPIを呼び出すアプリケーションで二項演算子を表すクラスの実装に使えるようにすることが目的なので」

との記載があります。よって、解答は「ア」です。

∴ア:下位クラスを実装するクラスだけで使える

設問3

次の記述中の に入れる正しい答えを,解答群の中から選べ。ここで,プログラム6中のaには,設問1の正しい答えが入っているものとする。

 プログラム6は,ライブラリのパッケージ外で二項演算式を実装するテストとして,減算式を表すクラス Subtraction を実装したものである。
pm11_5.png
 プログラム6をテストするために,プログラム4のメソッド main の/* α */の行を図2に示す行に置き換えて実行したところ,図1に示した出力結果に加え,出力結果" "を得た。
pm11_6.png
解答群
  • ((2 + 5) - (2 - 5))
  • ((7) - (-3))
  • (2 + 5 - 2 - 5)
  • (2 + 5) - (2 - 5)
  • 0
  • 10
解答選択欄
  •  
  •  

解説

図2「メソッドmainの/* α */の行を置き換える行」を1つずつ分解します。

まず、最も内側の new Subtraction(two, five) を、System.out.println(new Subtraction(two, five)) とした場合、Subtraction インスタンスの toString() メソッドを呼び出します。Subtraction クラスには toString() メソッドがありませんが、スーパークラスの BinaryOperatorExpression クラスに実装されています。また、getOperator() メソッドはサブクラスの Subtraction クラスで実装されています。よって、これを実行すると"(2 - 5)"が返ります。

add は、図1「メソッドmainの出力結果」と、設問1cの内容の通り、(2 + 5) を返します。

最後に、外側の Subtraction です。
第1引数に add を、第2引数に Subtraction インスタンスを渡しています。これら引数が left、right に該当するため、"((2 + 5) - (2 - 5))"が返ります。

よって、解答は「ア」です。

∴ア:((2 + 5) - (2 - 5))

設問4

次の記述中の に入れる正しい答えを,解答群の中から選べ。

 Bさんから,更に次の指摘を受けた。
 "オブジェクトの等価についての考慮も必要である。例えば, を評価すると,二つのインスタンスが表す値が等しいので true になるべきだが,今のクラス Constant の実装では false になる。"
解答群
  • new Constant(9) == new Constant(9)
  • new Constant(9).equals(new Constant(9))
  • new Constant(9).evaluate() == new Constant(9).evaluate()
  • new Constant(9).evaluate().equals(new Constant(9).evaluate())
解答選択欄
  •  
  •  

解説

オブジェクトの同一性、同値性に関する設問です。
同一性
同じオブジェクトを参照していることです。 == で比較します。
同値性
オブジェクトの値が等しいことです。比較する値は各クラスによって独自に実装します。
問題文に「二つのインスタンスを表す値が等しいので true になるべきだが、今のクラス Constant の実装では false になる」という記述があります。

同値性チェックで true にしたい場合、Javaでは equals() メソッドをオーバーライドします。equals() メソッドは、java.lang.Object クラスに実装されており、全てのクラスは Object クラスのサブクラスです。よって、オーバーライドしない場合、Object クラスの equals() メソッドが呼ばれます。※Object.equals() は同一性チェックです。

よって、 には equals() メソッドでの同値性チェックを表す「イ」が入ります。
  • 同一性チェックのため問題文に合いません。
  • 正しい。
  • 同一性チェックのため問題文に合いません。
  • コンパイルエラーです。evaluate() メソッドの戻り値はプリミティブ型(int型)です。
∴イ:new Constant(9).equals(new Constant(9))

ちなみに、Constantクラスにequalsメソッドを実装する場合の例は下記です。
@Override
public boolean equals(Object obj) {
  if (obj instanceof Constant) {
    return this.evaluate() == ((Constant)obj).evaluate();
  } else {
    return false;
  }
}
※equals() メソッドをオーバーライドする場合は hashCode() メソッドもオーバーライドするという決まりになっています。
https://docs.oracle.com/javase/jp/8/docs/api/java/lang/Object.html#equals-java.lang.Object-

Pagetop