#試験時間は短い。ひっかけに早く気づければ、さっさと次の問題に進める!#
Java Bronze試験に合格しました!!
これから受けようという方にお伝えしたいのが、この試験はひっかけ問題…というか、長々コードを読ませておいて、最後の1行で「え、これコンパイルエラーになるじゃん!コード読んでた時間無駄だったじゃん!!」となる問題がけっこうあるということ。
実際に試験で出たものと問題集で出たもののなかから、ひっかけ問題のパターンの一覧を作ってみました。
※コメント大歓迎です!Java初心者のため、内容が間違っていないかとても心配しています。なにか気になる点があれば何でも指摘していただきたいです。
===================
出題傾向、押さえるべきポイントなど詳しくまとめたページをつくりました!
⇒ Java Bronze 7/8 合格体験記!「ここをもっと勉強しておけばよかった…」と本番で後悔した箇所まとめ&オブジェクト指向ポイント解説
#byte型、short型のひっかけ#
・byte型に128より大きい整数が、short型に32767より大きい整数が代入されている
byte a = 200; //大きすぎてダメ!
short b = 50000; //大きすぎてダメ!
byte型で扱える値は**-128~127**、short型で扱える値は**-32768~32767です。
扱える範囲にない整数が代入されるとコンパイルエラー**になります。
出題コードでは何食わぬ顔で代入されていたりするので、そんな問題を見たら迷わず「コンパイルエラーになるな」と判断しましょう。
#long型、float型のひっかけ#
・long型でしか扱えないリテラルの最後にlやLがない
「リテラル」というのは変数の中身のことで、多くの場合イコールの右側にあるものです。「a = 100;」だったら100がリテラルです。
long型は最後に大文字のLまたは小文字のlをつけるルールがありますが、全ての場合に付けなければいけないわけではありません。
たとえば、
class Sample {
public static void main(String[] args) {
long l = 1000;
}
}
これはLやlが付いていなくてもOKで、
class Sample {
public static void main(String[] args) {
long l = 100000000000;
}
}
これはコンパイルエラーになってしまいます。
違いは「リテラルがint型で扱える範囲内ならばLやlをつけなくてOK、int型で扱える範囲外ならばLやlをつけなければならない」ということです。
末尾にLやlがついていない整数は(long型と宣言していようと)最初に自動的にint型として扱われるため、int型の範囲を超えているとエラーになってしまいます。
int型で扱える範囲は**-2,147,483,648 〜 2,147,483,647**。「だいたいプラスマイナス21億くらい」と覚えておけば大丈夫だと思います。
・float型の小数リテラルの最後にfやFがない
class Sample {
public static void main(String[] args) {
float f = 3.14;
}
}
float f = 3.14の部分でコンパイルエラーになってしまいます。
float型で小数を扱う場合に関しては、絶対に末尾にFかfをつけなければなりません。
#if文のひっかけ#
・条件式のなかに「==」ではなく「=」(※boolean型は除く)
条件式:if文で、最初の「if」の次にある括弧部分
class Sample {
public static void main(String[] args) {
int a = 1, b = 2;
if(a = 1) //単体のイコールはダメ
System.out.println("a = 1");
}
}
if(a = 1)の部分でコンパイルエラーになります。
a = 1 という式は「変数aに1を代入する」という意味ですが、
a == 1 という式は「aと1は等しいかどうか比較する」という意味で、式の値がtrueかfalseに必ず定まるというものです。if文は代入ではなく比較をすることでその後の処理を判断するものなので、==を使わなければいけません。
ただしboolean型の場合は特殊で、
boolean b = true;
if(b = false)
System.out.println("b is false");
という風に単独の「=」を使って代入もできるし、
boolean b = true;
if(b == false)
System.out.println("b is false");
という風に「==」を使って、すでに宣言された変数とtrue,falseを比較することもできます。
↑初投稿時、「boolean型では『=』しか使わない」という誤った説明をしていましたが、コメントでご指摘をいただき訂正いたしました。申し訳ございません。
正しくは、代入の場合「=」、比較の場合は「==」と両方使えます。
#演算子のひっかけ#
・ありえない演算子が使われている(and,orなど)
class Sample {
public static void main(String[] args) {
int x = 10, y = 20:
if (x == 10 and y == 20) {}
if (x == 10 or y == 20) {}
}
}
上の例の2つのif文はどちらもコンパイルエラーになります。
Javaの関係演算子のなかに、英単語の「and」や「or」はありません。
#elseのひっかけ#
・elseのあとに条件式がついている
class Sample {
public static void main(String[] args) {
int x = 0, y = 5;
if (x++ < 0)
System.out.println("1 ");
else if (x < y)
System.out.println("2 ");
else (y == 5) //ここでエラーになる
System.out.println("3 ");
}
}
else(y == 5)の部分でコンパイルエラー
elseは「if文の条件がどれも当てはまらない場合」という意味なので、そこに条件式をつけることはできません。if文が問題に出てきたら、まず最後のelseの部分を確認すると良いと思います。
#文字列に「-=」(引き算)が使われている#
class Sample {
public static void main(String[] args) {
String str = "Hi!";
String str2 = "How are you?";
str += str2;
str -= str2; //ここでエラーになる
System.out.println(str);
}
}
str -= str2 の部分でコンパイルエラー
String型には+演算子を使うことはできますが、-演算子は使えません。
#for文のひっかけ#
・スコープ範囲外にSystem.out.println()がある
class Sample {
public static void main(String[] args) {
for (int i = 0; i < 5; i++) {
if (i > 3) break;
}
System.out.println(i);
}
}
これはコンパイルエラーになってしまいます。
最後に変数iの値を出力する命令(System.out.println)が出てきますが、
for文内で宣言された変数は、for文の外から参照することができません。
よって、「System.out.println(i);」は宣言されていない変数を出力する命令になってしまうのでコンパイルエラーとなってしまうのです。
なお、変数をfor文の外で宣言している場合、エラーにはなりません。
class Sample {
public static void main(String[] args) {
int num = 1;
for (num = 0; num < 3; ++num) {
num *= 2;
}
System.out.println(num);
}
}
この場合は、for文以外のところ(3行目)で「int num = 1;」として変数numをしっかり宣言しています。for文の中でnumに対して行われた値の変更は、3行目のnumにも保存されます。なのでSystem.out.println(num)を実行し、3という出力を得ることができます。
#do-while文のひっかけ#
・「do while (条件式) {処理内容}」というありえない文法が使われている
do-while文の定義は、
**do {処理内容} while (条件式);**です。do whileと単語が連なることはあり得ません。
#switch文のひっかけ#
・式にlong型が指定されている(ほかのパターンもあるかも)
式というのは、switch文の最初の「switch」の直後の括弧部分です。
class Sample {
public static void main(String[] args) {
long i = 0;
switch(i){
case 0: System.out.println("case0 ");
case 10: System.out.println("case10 ");
}
}
}
式に入れられる値は、byte,char,short,int,String,enum の型のものしか認められません。上の例では適用できないlong型の値を式に入れているためコンパイルエラーになります。long型に限らず、上で挙げた6種類の型以外のものはすべてコンパイルエラーになるので、switch文が出たら注意してください。
#staticメソッドのひっかけ#
・staticなメソッドが、非staticなメソッドを呼び出している
class Sample {
static int num;
void methodA() {num++;}
public static void main(String[] args) {
methodA();
System.out.println(num);
}
}
宣言時にstatic修飾子がついたメソッドをstaticメソッドと言います。
staticメソッドは、非staticメソッド(または非static変数)を呼び出すことができません。
上の例では、2行目にあるmethodAメソッドは宣言に「static」という言葉がないため非staticメソッド、4行目にあるmainメソッドは宣言に「public static void」とあるためstaticメソッドです。
5行目でmainメソッド(staticメソッド)からmethodAメソッド(非staticメソッド)を呼び出しているためコンパイルエラーになります。
#thisのひっかけ#
・コンストラクタ定義の中で、先頭行ではない場所で記述されている
//コンストラクタ部分のみ記述
Foo(int b) {
this.b = b;
}
Foo(int a, int b) {
this.a = a++;
this(++b);
//先頭行にないのでコンパイルエラー
}
public static void main(String[] args) {
int a = 3;
int b = 5;
Foo obj = new Foo(a,b);
}
コンストラクタ内で「this(引数)」とすると、その引数の個数やデータ型に応じてまた別のコンストラクタを呼び出して処理をすることができます。そのときのルールとして、「this(引数)」はコンストラクタ定義の{}内の先頭行に書かなければいけません。
たとえば上の例では、インスタンス変数objが持つaとbという二つの引数に対して、aに関しては4行目から始まるコンストラクタの処理を、bに関しては1行目から始まるコンストラクタの処理をしたいのでthis(++b)としていますが、このように他のコンストラクタに渡してしまいたい引数がある場合は先頭行で真っ先に宣言しなければいけません。
よって、
Foo(int a, int b) {
this(++b);
//入れ替えて先頭行にしたのでOK
this.a = a++;
}
このように入れ替えればコンパイルに成功し、正しく実行されます。
以上です。
添削・意見を大歓迎していますので、記載内容に間違いがあればご指摘ください!
受験を考えていらっしゃる方の助けになれれば幸いです。