JavaSilver対策〜3秒で解ける問題〜

「JavaSilver」の対策記事となります。

JavaSilverの問題ですが、実は中には問題文もしくは選択肢を見れば速攻で解くことができる問題があります。

本来であればしっかりと理解した上で解くのが良いのですが、正直いくつかのポイントを暗記さえしていれば考えなくとも簡単に解けてしまうものです。

今回はふ〜んくらいの心づもりでこの記事を見ていただければと思います。
では、実際に一つ一つ見ていきましょう！
<h1>目次</h1>

[1. varによる変数宣言](#varによる変数宣言)
　- [例題1-1](#例題1_1)
　- [例題1-2](#例題1_2)
　- [例題1-3](#例題1_3)
[2. StringクラスとStringBuilderクラスのメソッド](#stringクラスとstringbuilderクラスのメソッド)
　- [例題2-1](#例題2_1)
　- [例題2-2](#例題2_2)
[3. Switch文](#switch文)
　- [例題3-1](#例題3_1)
　- [例題3-2](#例題3_2)


<h2>varによる変数宣言</h2>
そもそもvarについて軽く説明しておこうと思います。

Javaで<font color="SteelBlue"><strong>ローカル変数型推論</strong></font>が使用可能になったことで、ローカル変数の宣言時に型をvarと記述して利用することができるようになりました。

詳しい説明は省きますが、
<strong>記述した処理から型が予測できる場合はその型をわざわざ指定しなくてもvarを使っていいよ</strong>
という感じです。

そんな<span style="text-decoration: underline;">varによる変数宣言の問題はほぼ高確率で出題される</span>ので押さえておきましょう。

今回抑える大切なポイントはこちらです。

:::note
<strong><font color="cc005f">”ローカル変数”</font>の<font color="SteelBlue">”初期化時のみ”</font>使用可能</strong>
:::

以下項目等では使用できません。

:::note 
<strong>・メソッドの引数</strong>
<strong>・コンストラクタの引数</strong>
<strong>・メソッドの戻り値</strong>
<strong>・フィールド（メンバ変数）</strong>
<strong>・catchブロック</strong>
<strong>・型推論できない為nullの代入はできない</strong>
:::

それでは、試験問題と類似した問題をいくつか見ていきましょう。
<h3>例題1_1</h3>

```java
Q1.変数宣言として正しいものは？

public class Main {
  var java = new ArrayList<String>(); //--(1)
  public static void main(String[] args){
    var var = "var"; //--(2)
    var value = null; //--(3)
    var num;  //--(4)
  }
}
```
解答と解説は以下のようになります。


```
----------- 解答 -----------

A. (2)のみ

----------- 解説 -----------

（1）インスタンス変数（メンバ変数）にvarは使用できない

（3）代入したnullでは型推論できない

（4）初期化せずにvarを使用することはできない

```


フィールド宣言されているものは論外ですし、初期化されていないのも論外なので一瞬で2択まで絞れます。

迷うとしたら（2）の

<strong><font color="#800000">・識別子としてvarが使えるのか?</font></strong>
<strong><font color="#800000">・nullが代入可能なのか？</font></strong>

ということですが、ここは今回せっかくなので覚えておきましょう。

varは予約語ではない</strong>ため識別子として使用することができます。(3)に関しては解説の通りなので「<font color="#06a4d4"><strong>varは識別子として使える</strong></font>」というのを理解しておけば3秒で解くことができる簡単な問題ですね。

「フィールド！、null！、初期化なし！」タンッ！、タンッ！、タンッ！とテンポ良く解答していきましょう（笑）

では、次の例題を見ていきましょう。
<h3>例題1_2</h3>


```java
Q2.4行目に挿入するコードで正しくコンパイルできるものはどれですか？
2つ選択してください。


class Test {
  public static void main (String args[]) {
    String[] strs = new String[]{"Java", "Silver"};
    // （insert code here）　---4行目
    }
  }
}

(1). for(var i = 0; i < strs.length; ++i){
(2). for(var var:strs){
(3). for(var i = 0, i2 = 0; i<strs.length;i++){
(4). for(var str = null : strs){
```
解答と解説は以下のようになります。

```
----------- 解答 -----------

A. (1), (2)

----------- 解説 -----------

（3）var型は複数同時に宣言することができない

（4）拡張for文ではそもそも変数の初期化ができない

```

この問題の迷うポイントは

<strong><font color="#800000">・var型で複数同時に宣言することができるのか？</font></strong>

だと思いますが、var型では複数同時宣言はできないのでこれも今回覚えておくようにしましょう。

となるとそこを押さえておけば、
<strong>
(1)：ローカル変数の初期化 + 0が代入 → int型の型推論が可能
(2)：配列がString[]型 → 型推論が可能
</strong>

そして共通点として(2)(4)は<font color="#06a4d4"><strong>拡張for文</strong></font>の記述の仕方


:::note
<strong>for(<font color="Crimson">型</font>　<font color="#ed4f0c">変数</font>：<font color="#ed4f0c">配列</font>or<font color="SlateBlue">コレクション</font>)</strong>
:::

を理解していればやはりこの問題も瞬殺できるわけですね。

では、次は少し難易度を上げた問題も見てみましょう。
<h3>例題1_3</h3>


```java
Q.4,5行目に挿入することで配列vの全要素を出力できるコードはどれか？
2つ選択してください。

class Test {
  public static void main (String[] args) {
    var v = new int[][]{{100,200}, {300,400}};
    for( /*(insert code here)*/ ) {  //4行目
      for( /*(insert code here)*/ ) {  //5行目
        System.out.println(i + ":");
      }
    }
  }
}

(1). 4行目：var[] n : v
     5行目：var i : n

(2). 4行目：var n : v
     5行目：var i : n

(3). 4行目：int n : v
     5行目：var i : n

(4). 4行目：var n : v
     5行目：int i : n
```
解答と解説は以下のようになります。


```
----------- 解答 -----------

A. (2), (4)

----------- 解説 -----------

（1）配列もvar型として定義できるため、var[]はコンパイルエラーとなる

（3）外側のループはint型の配列を取得するため、int[] nが適切

```
一見複雑そうに見える問題ですが、今まで紹介してきた問題となんら変わりはありません。

この問題のポイントは

<strong><font color="#800000">・配列vが2次元配列のため、拡張for文を使用した際の受け取り側の型がどうなるのか</font></strong>

という点です。

<h4>外側のループ</h4>

`{100, 200}`と`{300, 400}`という配列をそれぞれ格納したいので、

:::note
<strong>受け取る方の型：<font color="#ed4f0c">int型の配列</font></strong>
:::
になっていないと文法的におかしくなります。


<h4>内側のループ</h4>


`100,200,300,400`というint型の数字を受け取るので,

:::note
<strong>受け取る方：<font color="#ed4f0c">int型</font></strong>
:::
である必要があります。

これを理解している前提でこの問題を見てみると、
<strong>
(1)：var[ ]は存在しないのでそもそもおかしい
(2)：外も内もvar型で受け取ているため安全牌
</strong>
となると残り2つですが、
<strong>
(3)：解説の通り外側ループでint[]nとなっていない時点でOUT
</strong>
です。

このようにある程度暗記すべきポイントを押さえておくだけで<strong>var問題は瞬殺</strong>できるので出たらラッキー！という感覚で挑みましょう。

たまに、ぬるっと別の知識を問うような問題にvarが登場しており、そこが原因でエラーになるみたいな問題もありますが今回の部分を押さえておけばきっと大丈夫なはずです。


<h2>StringクラスとStringbuilderクラスのメソッド</h2>
Javaでは文字列を扱うデータ型として<strong><font color="#06a4d4">String型</font></strong>と<strong><font color="#cc005f">StringBuilder型</font></strong>があります。

&nbsp;
<strong><font color="#06a4d4">String型</font></strong>
初期化されたString型の変数に別の文字列を再代入すると<strong><font color="#ed4f0c">元の文字列はそのまま</font></strong>で、新しい文字列が生成され、変数の参照先がそちらに切り替わります。

<strong><font color="#cc005f">StringBuilder型</font></strong>
初期化されたStringBuilder型の変数に対して文字列の追加や削除などが可能で,
<strong><font color="#ed4f0c">保持する文字列を直接操作</font></strong>できます。

:::note
<strong>
・<font color="#06a4d4">String型</font>は文字列を新たに生成

・<font color="#cc005f">StringBuilder型</font>は保持する文字列を直接操作可能
</strong>
:::


</div>
JavaSilverで良く出題されるメソッドは結構限られているので下記メソッドをそれぞれ覚えておけば割と大丈夫です。

:::note
<strong>
<font color="#06a4d4">Stringクラス</font>

・<font color="#d93609">charAt()</font>：引数にある文字を返す

・<font color="#d93609">equals()</font>：引数の文字列を同じか比較する

・<font color="#d93609">intern()</font>：文字列プールの中にある一意の文字列を返す

・<font color="#d93609">indexOf()</font>：引数の文字が最初に出現する位置を返す

・<font color="#d93609">length()</font>：文字の数を返す

・<font color="#d93609">※replace()</font>：第1引数の文字を、第2引数で指定した文字に置き換え、結果を返す

・<font color="#d93609">substring()</font>：引数で指定した位置から最後までの部分の文字列を返す
</strong>
:::

:::note
<strong>
<font color="#cc005f">StringBuilderクラス</font>

・<font color="#d93609">append</font>：引数で指定された文字列を現在の文字列に追加する

・<font color="#d93609">insert()</font>：引数で指定された文字列を、引数で指定された位置にある文字の前に挿入する

・<font color="#d93609">replace()</font>：第1引数から第2引数の位置の1つ前までの位置にある文字を、第3引数で指定された文字列に置換する

・<font color="#d93609">delete()</font>：第1引数から第2引数の位置の1つ前までの位置にある文字を削除する

・<font color="#d93609">substring()</font>：引数で指定した位置から最後までの部分の文字列を返す
:::


これらを踏まえた上で例題を見ていきましょう。
<h3>例題2_1</h3>


```java
Q.このコードをコンパイルおよび実行するとどのような結果になりますか？
1つ選択してください。


class Test {
  public static void main (String[] args) {
    String str = "Hello Java SE 11.";
    str.substring(6);
    str = str.intern();
    System.out.println(str);
  }
}

(1). Hello
(2). Hello java SE 11.
(3). true
(4). false
```


```
----------- 解答 -----------

A. (2)

----------- 解説 -----------

・substring()メソッドで6文字目以降の文字列を切り出しているが、
切り出した文字列を変数で受け取っていない。

・intern()メソッドによって変数strが参照している文字列を返すが、
結果的に同じ文字列「Hello Java SE 11.」を変数strに格納する。
```

この問題はString型のメソッドに関する初歩的な問題ですが、<strong>型がStringでかつStringクラスのメソッドの結果を変数で受け取っていなければ問答無用でスルーして大丈夫</strong>です。今回の場合はスルーした結果、変数strは何も変わっていないのでintern()の結果も変わりません。

メソッドの役割とStringクラスに関して理解しておけばここは秒殺できる問題ですね。

では、次は少し難易度を上げた問題を見てみましょう。
<h3>例題2_2</h3>


```java
Q.このコードをコンパイルおよび実行するとどのような結果になりますか？
1つ選択してください。

class Message {
  public static void main (String[] args) {
    StringBuilder sb = new StringBuilder();
    String msg = "Thankyou";
    sb.append("Thank").append("you");

    if(msg == sb.toString()) {
      System.out.println("Same Object");
    }
    if(sb.equals(msg.toString())) {
      System.out.println("Same String");
      }
  }
}

(1). Same Object Same String
(2). Same String
(3). Same Object
(4). 何も出力されない
```

```
----------- 解答 -----------

A. (4)

----------- ポイント -----------

・変数sbはStringBuilder型であること

・toString()メソッドによってそれぞれの文字列をString型で返していること

・==演算子とequals()メソッドでそれぞれ何を比較しているのか
```

ざっくりポイントでまとめましたが、順に説明していきます。

変数msg,sbに格納されている文字列はどちらも「Thankyou」です。
ここまでは大丈夫かと思いますが、問題はif文です。

そもそも変数msgをイメージでいうと、
「Thankyou」という文字列の1塊がオブジェクト領域を持っており、その領域を参照しています。

一方で変数sbをイメージでいうと、
newして確保された領域に対して<strong><font color="#d93609">append()メソッド</font></strong>を使用して

<strong>『「T」「h」「a」「n」「k」「y」「o」「u」』</strong>

というふうに文字を追加しており、その領域を参照しています。

そして、次の比較部分がこの問題の重要な点となります。

:::note
<strong>
・==演算子は、<font color="#06a4d4">オブジェクトの参照情報</font>が一致すればtrue

・StringBuilderクラスのequals()メソッドも、<font color="#06a4d4">オブジェクトの参照情報</font>が一致すればtrue

・Stringクラスのequals()メソッドは、<font color="#d93609">オブジェクトが保持する文字列</font>が一致すればtrue
</strong>
:::

となると、<strong>変数msgとsbが参照している領域は別のオブジェクト</strong>なので1つ目のif文はfalseという判断ができます。

2つ目のif文ですが少し深い説明をすると、そもそも<strong>equals()メソッド</strong>は<strong>Objectクラスで定義</strong>されており、「<strong>同一性</strong>」を確認する仕様となっています（「同一性」はインスタンスそのものが同じかどうか）。

```java:Objectクラス
public boolean equals(Object obj) {
		return (this == obj);
	}
```

そして「同値性」を確認する場合はそのクラスでオーバーライドする必要がありますが、今回の問題におけるStringBuilderクラスではequals()メソッドがオーバーライドされていない為、「==演算子」と同様に「同一性」を確認しています。

ちなみに<strong><font color="#06a4d4">Stringクラス</font></strong>で「<strong>同値性</strong>」が判定できるのは<strong>再定義されているから</strong>です。

つまり、

:::note
<strong>
問題の2つのif文はどちらも「同一性」を確認していることになるため両方ともfalseとなり、結果的に「何も表示されない」のです。
</strong>
:::


初めは少し混同するかもしれませんが、これも理解してしまえばそこまで悩むような問題でもありません。

せっかくなので中身まで理解した上でこの記事を再度見返してみて下さい。これに関しては一瞬迷いが生まれそうなので早くても5秒くらいかかりそうですかね（笑）
わかりませんが...

<h2>Switch文</h2>
JavaSilverの問題においてはSwitch文も実は即答しやすい問題が多いのです。

大体よく問われるポイントは下記の3項目です。

:::note
<strong>①caseの値で変数が使われているかどうか</strong>

<strong>②Switch文の引数とcaseの値で型が同じかどう</strong>

<strong>③break文があるかどうか</strong>
:::


さて、これらを踏まえた上で例題を見ていきましょう。
<h3>例題3_1</h3>

```java
Q.このコードはコンパイルエラーとなります。
コンパイルエラーが発生する行は次のうちどれですか？
2つ選択して下さい。

public class Main {
  public static void main(String[] args) {
    final int num = 10;
    int val = 20;
    int data = 30;

    switch(val){ //6行目
      case num:  //7行目
        System.out.println("A ");
        break;
      case 10*2:  //10行目
        System.out.println("B ");
        break;
      case data:  //13行目
        System.out.println("C ");
        break;
      case "40":  //16行目
        System.out.println("D ");
        break;
    }
  }
}

(1). 6行目
(2). 7行目
(3). 10行目
(4). 13行目
(5). 16行目
```

```
----------- 解答 -----------

A. (4), (5)

----------- 解説 -----------

・numはint型の定数、val,dataはint型の変数のため、6,7行目は問題なし

・10行目は計算を行なっていますが、20という数値になるため問題なし

・13行目はcaseの値に変数を使用しているためコンパイルエラー

・16行目はcaseの値の型は文字列型であり、Switch文の引数のint型と異なるためコンパイルエラー
```


すでに上述したポイントの①と②が今回の問題の肝になっています。


まずSwitch文の問題が来たら次の順番で意識して下さい。

:::note
<strong><font color="#d93609">① Switch文の引数の「型」</font></strong>

<strong><font color="#d93609">② caseの値に変数がないか</font></strong>
:::

ここで引っかかるようならコード全部を見なくても即答ができるので、時短できる場合が実は多いのです。

では、次は少し難易度を上げた例題を見てみましょう。
<h3>例題3_2</h3>

```java
Q.このコードのコンパイルを行うとどのような結果になりますか？
1つ選択して下さい。

class Main {
    public static void main(String[] args){
        final int i = 7;
        final int j = 8;
        switch(i){ //5行目
            case i | j: //6行目
                System.out.println("foo");
                break;
            case 8:
                System.out.println("bar");
                break;
            case 2 | 5: //12行目
                System.out.println("baz");
                break;
        }
    }
}

(1). 5行目でコンパイルエラー   (2). 6行目でコンパイルエラー   (3). 12行目でコンパイルエラー
(4). fooを出力   (5). barを出力   (6). bazを出力
(7). 何も出力されない
```

```
----------- 解答 -----------

A. (6)

----------- 解説 -----------

・5, 6, 12行目はそれぞれ定数かリテラルであり型もSwitch文の引数と同じため問題なし

・ビット演算子「|」に関してそれぞれのケースで当てはまるかどうかを考えていく必要がある。
```

この問題ではSwtch文の知識に加えて「<strong>ビット演算子</strong>」についても理解しておく必要のある問題となっています。実際の試験でも1,2問は出題される問題なのでしっかり押さえておきましょう。

:::note
<strong>整数の値に対してビット単位で処理を行うために用意されている演算子。</strong>

<strong>・<font color="#d93609">AND演算子</font>：「a & b」で表され、左辺と右辺の同じ位置にあるビットを比較して、両方のビットが1の場合だけ1にする</strong>

<strong>・<font color="#06a4d4">OR演算子</font>：「a | b」で表され、左辺と右辺の同じ位置にあるビットを比較して、どちらかのビットが1であれば1にする</strong>
:::


まずこの問題の6行目では「7 | 8」という形で比較されていますが、これをそれぞれ2進数で表すと以下のようになります。

<strong>7　→　<font color="#06a4d4">2²</font> + <font color="#06a4d4">2¹</font> + <font color="#06a4d4">2º</font>　よって「<font color="#d93609">0111</font>」と表すことができます。</span></strong>

<strong>8　→　<font color="#06a4d4">2³</font>　よって「<font color="#d93609">1000</font>」</strong>

<strong>「<font color="#d93609">0111</font> | <font color="#d93609">1000</font>」で比較すると、「<font color="#d93609">1111</font>」となるため「15」となる
</strong>

よって「case i | j」の場合ではないので何も処理されず次のcaseへと移りますが、次の「case 8」でもないのでこちらも何も処理ざれず次のcaseへと移ります。

「case 2 | 5」の場合も先ほどと同様に「OR演算子」の考え方で見ていきます。

「<strong><font color="#d93609">010</font> | <font color="#d93609">101</font></strong>」の比較となるので、その結果「<strong>111</strong>」となります。「<strong>111</strong>」を10進数で表すと「<strong>7</strong>」となるので「<strong>baz</strong>」が出力されることになります。

Switch文とビット演算子はセットで出題されるので必ず押さえて、確実に点数稼ぎにつなげていきましょう！


いかがでしたでしょうか？

今回の記事では瞬殺できるみたいな感じで言っていますが、もちろん小さなミスで落とすわけにはいかないので本番ではもうちょっとゆっくり解いても時間は十分余ります。

ですが、今回紹介した問題だけでなく他のざまざまな問題でも、暗記しておけばサラッと解けるものは多いです。

問題を解く時間を半分に短縮して、より効率の良い勉強に繋げていきましょう。

きっとそれが試験合格への近道にもなりますし、より深い理解へ繋がります。