「JavaSilver」の対策記事となります。
JavaSilverの問題ですが、実は中には問題文もしくは選択肢を見れば速攻で解くことができる問題があります。
本来であればしっかりと理解した上で解くのが良いのですが、正直いくつかのポイントを暗記さえしていれば考えなくとも簡単に解けてしまうものです。
今回はふ〜んくらいの心づもりでこの記事を見ていただければと思います。
では、実際に一つ一つ見ていきましょう!
目次
1. varによる変数宣言
- 例題1-1
- 例題1-2
- 例題1-3
2. StringクラスとStringBuilderクラスのメソッド
- 例題2-1
- 例題2-2
3. Switch文
- 例題3-1
- 例題3-2
varによる変数宣言
そもそもvarについて軽く説明しておこうと思います。Javaでローカル変数型推論が使用可能になったことで、ローカル変数の宣言時に型をvarと記述して利用することができるようになりました。
詳しい説明は省きますが、
記述した処理から型が予測できる場合はその型をわざわざ指定しなくてもvarを使っていいよ
という感じです。
そんなvarによる変数宣言の問題はほぼ高確率で出題されるので押さえておきましょう。
今回抑える大切なポイントはこちらです。
”ローカル変数”の”初期化時のみ”使用可能
以下項目等では使用できません。
・メソッドの引数
・コンストラクタの引数
・メソッドの戻り値
・フィールド(メンバ変数)
・catchブロック
・型推論できない為nullの代入はできない
それでは、試験問題と類似した問題をいくつか見ていきましょう。
例題1_1
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)の
・識別子としてvarが使えるのか?
・nullが代入可能なのか?
ということですが、ここは今回せっかくなので覚えておきましょう。
varは予約語ではないため識別子として使用することができます。(3)に関しては解説の通りなので「varは識別子として使える」というのを理解しておけば3秒で解くことができる簡単な問題ですね。
「フィールド!、null!、初期化なし!」タンッ!、タンッ!、タンッ!とテンポ良く解答していきましょう(笑)
では、次の例題を見ていきましょう。
例題1_2
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文ではそもそも変数の初期化ができない
この問題の迷うポイントは
・var型で複数同時に宣言することができるのか?
だと思いますが、var型では複数同時宣言はできないのでこれも今回覚えておくようにしましょう。
となるとそこを押さえておけば、
(1):ローカル変数の初期化 + 0が代入 → int型の型推論が可能
(2):配列がString[]型 → 型推論が可能
そして共通点として(2)(4)は拡張for文の記述の仕方
for(型 変数:配列orコレクション)
を理解していればやはりこの問題も瞬殺できるわけですね。
では、次は少し難易度を上げた問題も見てみましょう。
例題1_3
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が適切
一見複雑そうに見える問題ですが、今まで紹介してきた問題となんら変わりはありません。
この問題のポイントは
・配列vが2次元配列のため、拡張for文を使用した際の受け取り側の型がどうなるのか
という点です。
外側のループ
{100, 200}
と{300, 400}
という配列をそれぞれ格納したいので、
受け取る方の型:int型の配列
になっていないと文法的におかしくなります。
内側のループ
100,200,300,400
というint型の数字を受け取るので,
受け取る方:int型
である必要があります。
これを理解している前提でこの問題を見てみると、
(1):var[ ]は存在しないのでそもそもおかしい
(2):外も内もvar型で受け取ているため安全牌
となると残り2つですが、
(3):解説の通り外側ループでint[]nとなっていない時点でOUT
です。
このようにある程度暗記すべきポイントを押さえておくだけでvar問題は瞬殺できるので出たらラッキー!という感覚で挑みましょう。
たまに、ぬるっと別の知識を問うような問題にvarが登場しており、そこが原因でエラーになるみたいな問題もありますが今回の部分を押さえておけばきっと大丈夫なはずです。
StringクラスとStringbuilderクラスのメソッド
Javaでは文字列を扱うデータ型としてString型とStringBuilder型があります。
String型
初期化されたString型の変数に別の文字列を再代入すると元の文字列はそのままで、新しい文字列が生成され、変数の参照先がそちらに切り替わります。
StringBuilder型
初期化されたStringBuilder型の変数に対して文字列の追加や削除などが可能で,
保持する文字列を直接操作できます。
・StringBuilder型は保持する文字列を直接操作可能
・charAt():引数にある文字を返す
・equals():引数の文字列を同じか比較する
・intern():文字列プールの中にある一意の文字列を返す
・indexOf():引数の文字が最初に出現する位置を返す
・length():文字の数を返す
・※replace():第1引数の文字を、第2引数で指定した文字に置き換え、結果を返す
・substring():引数で指定した位置から最後までの部分の文字列を返す
・append:引数で指定された文字列を現在の文字列に追加する
・insert():引数で指定された文字列を、引数で指定された位置にある文字の前に挿入する
・replace():第1引数から第2引数の位置の1つ前までの位置にある文字を、第3引数で指定された文字列に置換する
・delete():第1引数から第2引数の位置の1つ前までの位置にある文字を削除する
・substring():引数で指定した位置から最後までの部分の文字列を返す
これらを踏まえた上で例題を見ていきましょう。
例題2_1
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型のメソッドに関する初歩的な問題ですが、型がStringでかつStringクラスのメソッドの結果を変数で受け取っていなければ問答無用でスルーして大丈夫です。今回の場合はスルーした結果、変数strは何も変わっていないのでintern()の結果も変わりません。
メソッドの役割とStringクラスに関して理解しておけばここは秒殺できる問題ですね。
では、次は少し難易度を上げた問題を見てみましょう。
例題2_2
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して確保された領域に対してappend()メソッドを使用して
『「T」「h」「a」「n」「k」「y」「o」「u」』
というふうに文字を追加しており、その領域を参照しています。
そして、次の比較部分がこの問題の重要な点となります。
・StringBuilderクラスのequals()メソッドも、オブジェクトの参照情報が一致すればtrue
・Stringクラスのequals()メソッドは、オブジェクトが保持する文字列が一致すればtrue
となると、変数msgとsbが参照している領域は別のオブジェクトなので1つ目のif文はfalseという判断ができます。
2つ目のif文ですが少し深い説明をすると、そもそもequals()メソッドはObjectクラスで定義されており、「同一性」を確認する仕様となっています(「同一性」はインスタンスそのものが同じかどうか)。
public boolean equals(Object obj) {
return (this == obj);
}
そして「同値性」を確認する場合はそのクラスでオーバーライドする必要がありますが、今回の問題におけるStringBuilderクラスではequals()メソッドがオーバーライドされていない為、「==演算子」と同様に「同一性」を確認しています。
ちなみにStringクラスで「同値性」が判定できるのは再定義されているからです。
つまり、
初めは少し混同するかもしれませんが、これも理解してしまえばそこまで悩むような問題でもありません。
せっかくなので中身まで理解した上でこの記事を再度見返してみて下さい。これに関しては一瞬迷いが生まれそうなので早くても5秒くらいかかりそうですかね(笑)
わかりませんが...
Switch文
JavaSilverの問題においてはSwitch文も実は即答しやすい問題が多いのです。大体よく問われるポイントは下記の3項目です。
①caseの値で変数が使われているかどうか
②Switch文の引数とcaseの値で型が同じかどう
③break文があるかどうか
さて、これらを踏まえた上で例題を見ていきましょう。
例題3_1
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文の問題が来たら次の順番で意識して下さい。
① Switch文の引数の「型」
② caseの値に変数がないか
ここで引っかかるようならコード全部を見なくても即答ができるので、時短できる場合が実は多いのです。
では、次は少し難易度を上げた例題を見てみましょう。
例題3_2
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文の知識に加えて「ビット演算子」についても理解しておく必要のある問題となっています。実際の試験でも1,2問は出題される問題なのでしっかり押さえておきましょう。
整数の値に対してビット単位で処理を行うために用意されている演算子。
・AND演算子:「a & b」で表され、左辺と右辺の同じ位置にあるビットを比較して、両方のビットが1の場合だけ1にする
・OR演算子:「a | b」で表され、左辺と右辺の同じ位置にあるビットを比較して、どちらかのビットが1であれば1にする
まずこの問題の6行目では「7 | 8」という形で比較されていますが、これをそれぞれ2進数で表すと以下のようになります。
7 → 2² + 2¹ + 2º よって「0111」と表すことができます。
8 → 2³ よって「1000」
「0111 | 1000」で比較すると、「1111」となるため「15」となる
よって「case i | j」の場合ではないので何も処理されず次のcaseへと移りますが、次の「case 8」でもないのでこちらも何も処理ざれず次のcaseへと移ります。
「case 2 | 5」の場合も先ほどと同様に「OR演算子」の考え方で見ていきます。
「010 | 101」の比較となるので、その結果「111」となります。「111」を10進数で表すと「7」となるので「baz」が出力されることになります。
Switch文とビット演算子はセットで出題されるので必ず押さえて、確実に点数稼ぎにつなげていきましょう!
いかがでしたでしょうか?
今回の記事では瞬殺できるみたいな感じで言っていますが、もちろん小さなミスで落とすわけにはいかないので本番ではもうちょっとゆっくり解いても時間は十分余ります。
ですが、今回紹介した問題だけでなく他のざまざまな問題でも、暗記しておけばサラッと解けるものは多いです。
問題を解く時間を半分に短縮して、より効率の良い勉強に繋げていきましょう。
きっとそれが試験合格への近道にもなりますし、より深い理解へ繋がります。