大変お世話になっております。
反逆する武士
uematu tubasaです。
初回投稿日時:2023年6月4日(令和5年6月4日)
完全なる自己満足記事です。
私の勉強の内容をアウトプットする記事です。
情報技術関連なので、政治経済系の記事をお読みになりたい場合はスルーしていただけると嬉しく思います。
型変換に関する基本的な問題
Javaというプログラミング言語は静的型付け言語と言われています。
型変換に関する基本的な認識を勉強しましょう。
大きな範囲の値を小さな変数に代入する場合は明示的なキャストが必要になります。
int a = 10;
short b = (short)a;
byte型の変数に整数リテラルを代入する場合、-128~127までの値ならbyte型の範囲内なので、コンパイルエラーになりません。
例:byte a = 128; ←範囲外のためコンパイルエラー
byte b = 127; ←範囲内のためコンパイルエラーにならず
さらに、byte型に対して2進数で値を格納することもあるが、以下はコンパイルエラーになる。
例:byte a = 0b10000000; ←コンパイルエラー(2進数⇒10進数だと128になるから)
例:int c = 2 * 3L; ←コンパイルエラー(int c = 6L;と同じ意味であり、int型にlong型のリテラルを代入しようとしている)
浮動小数点数リテラルの場合、初期状態としてはdoubleとなります。
したがって、以下のような記述はコンパイルエラーになります。
float c = 10.0; ⇒コンパイルエラー(型の不一致: double から float には変換できません)
◆◆試験対策◆◆
byte型の範囲⇒-128~127
short型の範囲⇒-32768~32767
◆◆個人的感想◆◆
int型の上位互換がlong型であり、float型の上位互換がdouble型。
したがって、下位互換の型から上位互換への代入は問題ないが、上位互換から下位互換の型へ代入する場合は注意。
さらに、その型が扱える数の範囲にも注意する
論理演算子の問題
複数の関係演算を組み合わせ、複雑な条件を指定するために使うのが論理演算子です。
この記事では重要な2つだけご紹介します。
a && b ⇒aという条件がtrueで、なおかつbという条件がtrueならばtrue
a || b ⇒aという条件がtrue、またはbという条件がtrueならばtrue
&&演算子はもしa(左の条件)がfalseを返すのであれば、b(右の条件)の処理を省略する。
||演算子はもしa(左の条件)がtrueを返すのであれば、b(右の条件)の処理を省略する。
問題:以下のプログラムを実行した場合に結果はどうなる?
int a = 10;
int b = 10;
if(10 < a && 10 < ++b){
a++;
}
System.out.println( a + b );
【1】20がコンソール出力される
【2】21がコンソール出力される
【3】22がコンソール出力される
【4】コンパイルエラー
【5】実行時に例外が発生
答え:【1】
if文の中には処理が入らず、左の条件だけでfalseとなるので、右の条件まで処理は進まない。
その結果、int型変数aとbは共に増えず、20がコンソール出力される。
同値性とequalsメソッドのオーバーライド問題
equalsメソッドは同値性を確認するためのメソッドです。
Objectクラスに定義されているため、すべてのクラスが引き継いでいます。
null以外の参照値xについて、x.equals(null)はfalseを返すというのは試験対策として覚える必要があります。
問題:以下のプログラムを実行した場合に結果はどうなる?
Object a = new Object();
Object b = null;
System.out.println(a.equals(b));
【1】trueがコンソール出力される
【2】falseがコンソール出力される
【3】コンパイルエラー
【4】実行時に例外が発生
正解:【2】
ちなみに、System.out.println(b.equals(a));の場合は実行時に例外(NullPointerException)が発生します。
文字列の同一性を確認する問題
Stringのインスタンスはダブルクオーテーションで括られた文字列を記述するだけで作成できます。
異なったString変数を宣言した場合、異なる参照が代入されます。
そのため、「==」で比較すると、通常の場合はfalseが返却されます。
しかしながら、以下のような記述の場合は「==」で比較すると、trueが返却されます。
String a = "sample";
String b = "sample";
System.out.println(a == b);
実行結果:コンソールにtrueが出力される。
これは「コンスタントプール」という仕組みがあるためです。
同じ文字列リテラルがプログラム内に再び登場すれば、定数用のメモリ空間にある文字列インスタンスへの参照が「使い回し」されます。
こうすることで、新しいインスタンスを作るような負荷もかからず、メモリ消費を抑制してプログラムを実行できるのです。
しかしながら、以下の記述だとまた違った値が返却されます。
String a = new String("sample");
String b = "sample";
System.out.println(a == b);
実行結果:コンソールにfalseが出力される。
解説:コンスタントプールは文字列リテラルを使ったときだけ有効です。
そのため、上記のようなコードの場合、new演算子を使ってプログラマーが明示的に「新しいインスタンスを作る」ことを記述した場合には、その都度、インスタンスが作られ、参照が異なります。
switch文のcase値として使用できる問題
case値として使用できる値は、以下の条件を満たす必要があります。
・条件式が戻す値と同じ値か互換性がある型であること。
・定数であるかコンパイル時に値を決めることができること。
・nullではないこと。
fainal int NUM = 0;
int num = 10;
switch(num){
case "10" : System.out.println();
break;
case num : System.out.println();
break;
case 2 * 5 : System.out.println();
break;
case NUM : System.out.println();
break;
}
実行結果:1つ目と2つ目のケースにてコンパイルエラー
switch文のbreakに関する問題
通常、switch文においてはcase値に合致する処理が事項されます。
処理が終われば、breakを使ってswitchを抜けるようにします。
仮にbreakを記述しなかった場合は、以降に現れるすべてのcase式の処理がbreakまで続きます。
int num = 10;
switch(num){
case 10 : System.out.println(’A’);
case 11 : System.out.println(’B’);
case 12 : System.out.println(’C’);
case 13 : System.out.println(’D’);
default : System.out.println(’E’);
}
実行結果はすべてのアルファベットがコンソールに出力される。
解説:仮にint num = 11だったら、A以外のアルファベットがすべて出力される。
さらに言えば、13のケースにbreakがあった場合、そこで処理が止まる。
【実務的な観点】
switchを記述する場合はbreakを忘れないように。
以上です。