【平成30年 秋】基本情報技術者 午後 問11 Java を解説します!

どうも、tatsuです!

今回はつい先日行われた、平成30年 秋 基本情報技術者試験 の午後問題 問11 Javaを解説していきたいと思います!

Javaが一番得意なのでJavaしか解説しないです。笑

問題と解答はコチラからどうぞ!
平成30年 秋 基本情報技術者試験 問題
平成30年 秋 基本情報技術者試験 解答

ちなみにJavaはPDFの57ページからです。

問1

空欄 a

aに関連するインターフェース・クラスは以下の3つです。

public interface Fragment {
  String replace(Map<String, List<String>> table);
}
public class Replacer 【 a 】 Fragment {
  // 省略
}
public class PassThrogh【 a 】 Fragment {
  // 省略
}

この形はインターフェースFragmentを実装しているので、答えは【ウ】implementsであるとわかります。

空欄 b, c

空欄bとcがあるTemplateParserです。

public class TemplateParser {
  static public Template parse(Reader reader) throws IOException {
    StringBuilder buf = new String Builder();
    List<Fragment> fragmentList = new ArrayList<>();
    int c;
    while((c = reader.read()) >= 0){
      switch (c) {
        case '<' :
          fragmentList.add(new 【 b 】);
          buf = new StringBuilder();
          break;
        case '>' :
          fragmentList.add(new 【 c 】);
          buf = new StringBuilder();
          break;
        default :
          buf.append((char) c);
      }
    }
    fragmentList.add(new PassThrough(buf));
    return 【 d 】;
  }
}

また、問題文より以下のことがわかります。

  • Replacerは置換指示(<>で囲まれた部分)を表す
  • PassThroughは置換指示以外(<>で囲まれていない部分)を表す
  • ひな形はフラグメントのリストとして表す

 
まあ以下のようなひな型があったら、

私の名前は<名前>です。

こんな感じにしたいってことです。

List<Fragment> list = new ArrayList<>();
list.add(new PassThrough("私の名前は"));
list.add(new Replacer("名前"));
list.add(new PassThrough("です。"));

 
そこでソースコードに戻ってみると、、

public class TemplateParser {
  static public Template parse(Reader reader) throws IOException {
    StringBuilder buf = new String Builder();
    List<Fragment> fragmentList = new ArrayList<>();
    int c;
    while((c = reader.read()) >= 0){
      switch (c) {
        case '<' :
          fragmentList.add(new 【 b 】);
          buf = new StringBuilder();
          break;
        case '>' :
          fragmentList.add(new 【 c 】);
          buf = new StringBuilder();
          break;
        default :
          buf.append((char) c);
      }
    }
    fragmentList.add(new PassThrough(buf));
    return 【 d 】;
  }
}

<の時と、>の時にはリストに格納して新しいStringBuilderを生成していますね。

そしてnewされるクラスはFragmentインターフェースを実装しているReplacerかPassThroughしかありません。
※Fragmentはインターフェースなのでインスタンス化できません。

そしてReplacer(もしくはPassThrough)クラスのコンストラクタを見てみると、、

public class Replacer 【 a 】 Fragment {
  // 省略
  
  Replacer(CharSequence cs) { key = cs.toString(); }

  // 省略
}

となっており、APIの説明をみると、StringBuilderがCharSequenceを実装していると書いてあります。

ということは空欄b, cの解答の選択肢は以下の2つに絞られます。

  • 【ア】Fragment(buf) ・・・ Fragmentはインスタンス化できない
  • 【イ】Fragment(c) ・・・ Fragmentはインスタンス化できない
  • 【ウ】PassThrough(buf)
  • 【エ】PassThrough(c) ・・・ PassThroughはcharを引数に取らない
  • 【オ】Replacer(buf)
  • 【カ】Replacer(c) ・・・ Replacerはcharを引数に取らない

 
もう一度TemplateParserのswitchの中身を見てみましょう。

case '<' :
  fragmentList.add(new 【 b 】);
  buf = new StringBuilder();
  break;
case '>' :
  fragmentList.add(new 【 c 】);
  buf = new StringBuilder();
  break;
default :
  buf.append((char) c);

一文字ずつbufに追加していって、<や>が来たらfragmentListに格納してまた新しくbufを作ってます。

<が来たってことは、ここからReplacerが始まるということですよね?
ということは今までのは?

そう、PassThroughです。

逆に、>が来たってことはReplacerが終わってPassThroughが始まるということですから、答えはこうなります。

空欄b :【ウ】PassThrough(buf)
空欄c :【オ】Replacer(buf)

空欄 d

まず空欄dがあるTemplateParserを見てみましょう。

public class TemplateParser {
  static public Template parse(Reader reader) throws IOException {
    StringBuilder buf = new String Builder();
    List<Fragment> fragmentList = new ArrayList<>();
    // 省略
    fragmentList.add(new PassThrough(buf));
    return 【 d 】;
  }
}

return をしているので、このメソッドの戻り値を確認します。

static public Template parse(Reader reader) throws IOException {

戻り値はTemplateなので、ここではTemplateインスタンスを返してあげないといけません。

 
そこでどのようにTemplateメソッドを作れば良いか、Templateクラスを確認します。

public class Template {
  List<Fragment> fragmentList;

  Template(List<Fragment> fragmentList) {
    this.fragmentList = fragmetnList;
  }

  // 省略
}

コンストラクタでList<Fragment>の引数を渡しています。

また、returnの前でちょうどList<Fragment>型のfragmentListを作っていますので、それを渡せばよいことがわかります。 

なので答えは、【ウ】new Template(fragmentList) です。

空欄 e

空欄eはTemplateクラスにあります。

public class Template {
  List<Fragment> fragmentList;

  Template(List<Fragment> fragmentList) {
    this.fragmentList = fragmetnList;
  }

  public String apply(Map<String, List<String>> table){
    StringBuilder sb = new StringBuilder();
    for (Fragment fragment : fragmentList) {
      sb.append(fragment.replace(【 e 】));
    }
    return sb.toString();
  }
}

これですが、fragment.replaceを使っていますよね。

 
なのでFragmentインターフェースのreplaceメソッドの実装を見てみましょう。

public interface Fragment {
  String replace(Map<String, List<String>> table);
}

Map<String, List<String>>型の引数を渡すことがわかります。

 
Templateクラスに戻ってみると、、

public class Template {
  // 省略

  public String apply(Map<String, List<String>> table){
    StringBuilder sb = new StringBuilder();
    for (Fragment fragment : fragmentList) {
      sb.append(fragment.replace(【 e 】));
    }
    return sb.toString();
  }
}

applyメソッドの引数にまんまMap<String, List<String>> tableが渡ってきていますね♪

これをそのまま渡してあげればOKです。

なので答えは、【エ】table です。

問2

空欄 f

fでは新たなcaseを追加して、\の後の一文字は<や>も通常文字として扱うようにしたいみたいです。

caseをとりあえず追加してみたソースは以下になります。

public class TemplateParser {
  static public Template parse(Reader reader) throws IOException {
    StringBuilder buf = new String Builder();
    List<Fragment> fragmentList = new ArrayList<>();
    int c;
    while((c = reader.read()) >= 0){
      switch (c) {
        case '<' :
          fragmentList.add(new 【 b 】);
          buf = new StringBuilder();
          break;
        case '>' :
          fragmentList.add(new 【 c 】);
          buf = new StringBuilder();
          break;
        case '\\' :
          【 f 】
        default :
          buf.append((char) c);
      }
    }
    fragmentList.add(new PassThrough(buf));
    return 【 d 】;
  }
}

fでは\の次の1文字をbufに追加したいです。

次の文字を取得する方法はwhileの条件にもなっているreader.read()です。

これをdefault部分と同じようにbufに格納してあげればいいので、buf.append((char) reader.read())で終了!

ではありません!

switch文の特徴なのですが、break;で処理を終わらせてあげないと次の(今回はdefault)判定に進んでしまいます。

なのでこのままだと\の次の文字が2重に格納されてしまうのです。

 
よってbreakもいれてあげて、答えは【オ】buf.append((char) reader.read()); breakです。

Javaを正確に解くコツ

Java問題で素早く満点を取るために、いくつかのコツをお教えします。

問題を読まなくても答えられる箇所には敏感に

問題を読まなくても、ソースコードを見れば答えられる箇所というものが存在します。

といっても基本的なJavaの知識は必要になりますが。

今回で言うと、問1-a・問1-d・問1-eです。

忘れちゃった方は解説をもう一度読んでみてください。

「Javaプログラムで使用するAPIの説明」を読みながら解く

「Javaプログラムで使用するAPIの説明」(PDFの75ページ~)、ちゃんと読んでますか~??

実務でバリバリJavaのコードを書いているなら見なくてもわかるでしょうけど、学生さんは以下のクラス知っていましたか?

  • List(ArrayList)
  • Map
  • StringBuilder

わからない箇所が問題にあまり関わらなそうならほっといていいですが、問題に関わる箇所ならとりあえずAPIの説明を見る癖をつけましょう

ちなみに簡単な説明は以下を参考にしてください。

List(ArrayList)

// <>の中に指定したオブジェクトを配列のように管理するAPIです
// newの後の<>の中は省略できます。※new ArrayList<String>()とも書けます
List<String> list = new ArrayList<>();
// 変数名.addで指定したオブジェクト(今回はString)を格納することができます
list.add("おはよう");
list.add("こんにちは");
list.add("こんばんは");

// 変数名.get(添え字)で値を取り出すことができます
// resultの中身は「おはよう」です
String result = list.get( 0 );

Map

// キーと値の組合せで値を管理するAPIです
// <>の中にカンマ区切りでキーと値の型を指定します
// newの後の<>の中は省略できます。※new HashMap<String, String>とも書けます
Map<String, String> map = new HashMap<>();
// 変数名.putでキーと値を格納することができます
map.put("1", "ONE");
map.put("5", "FIVE");
map.put("code", "akljf;e");

// 変数名.get(キー)で値を取り出すことができます
// oneの中身は「ONE」です
String one = map.get("1");

StringBuilder

// 文字列を結合したり、様々な操作ができるAPIです
StringBuilder sb = new StringBuilder();
// 変数名.appendで文字や文字列等を格納していくことができます
// 格納された文字はすべて繋がります
sb.append('A');
sb.append('B');
sb.append('C');

// resultの中身は「ABC」です
String result = sb.toString();

まとめ

基本情報技術者のJava問題はその名の通りJava言語の最低限知識が必須です。

最低限と書いた理由は、みたことないクラスはAPIの説明に載っていることがほとんどだからです。

今後基本情報技術者試験を受験される方は、今回お伝えしたコツを実践して満点を取ってもらえたらうれしいです。

それでは!

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です