JavaのBooleanクラスの==比較
概要
JavaはObject同士を==で比較した際の戻り値がちょっと厄介です。
よくあるのが、Stringを==比較した場合に、同じ文字列が入ってるのに結果がtrueになったりfalseになったりするというものです。
では、BooleanのObjectを==で比較した場合は、どんな感じの結果になるのでしょう。
よくあるのが、Stringを==比較した場合に、同じ文字列が入ってるのに結果がtrueになったりfalseになったりするというものです。
では、BooleanのObjectを==で比較した場合は、どんな感じの結果になるのでしょう。
使用しているJavaのバージョン
JRE 1.6.0_07
実際に比較してみた
コード内で使っているBoolean.TRUEというのは、Booleanが持っているpublic static finalでtrueなBooleanオブジェクトです。
/** Boolean Objectをいろいろ比較してみる */
Boolean b;
// new Booleanすると、新しいObjectが生成される
// なので、==比較の結果はfalseになる
b = new Boolean(true);
System.out.println( b == Boolean.TRUE );
// => false
// equalsで比較すれば、もちろんtrue
b.equals( Boolean.TRUE );
// => true
// valueOfを使用すると、Boolean.TRUEと同じObjectが返されるようです
// なので、Boolean.TRUEと==比較しても、trueになります
// 新しいObjectが生成されないので地球に優しいですね
b = Boolean.valueOf(true);
System.out.println( b == Boolean.TRUE );
// => true
// Autoboxingすると、valueOfと同義で扱われるので、trueになります
// Integerでもそうでしたが、下手にnewとか書くよりも、
// autoboxingで任せておけば、勝手に一番軽いの選んでくれるような気がします
b = true;
System.out.println( b == Boolean.TRUE );
// => true
// 文字列でvalueOfしてもOKです
b = Boolean.valueOf("true");
System.out.println( b == Boolean.TRUE );
// => true
こういう結果になる理由
JavaのBooleanは、Boolean.TRUEとBoolean.FALSEという定数を持っています。これは中の人的には、こんな風に定義しています。
Boolean.valueOf(boolean)を使用した場合は、こんな感じで値が返されます。
こうしてみていると、new Booleanと書かなければ、Booleanは==で比較してもOKなような気もしなくもないです。
Booleanのequalsメソッドはこんなことをしています。
まぁ、そんなわずかの処理の為に、==比較みたいなバグの元になるような記述を入れるのはJavaらしくないですが。
public static final Boolean TRUE = new Boolean(true);
public static final Boolean FALSE = new Boolean(false);
つまり、実行する前からTRUEとFALSEのObjectを1つずつ定数としてnewして保持してしまっているわけです。Boolean.valueOf(boolean)を使用した場合は、こんな感じで値が返されます。
public static Boolean valueOf(boolean b) {
return (b ? TRUE : FALSE);
}
Boolean内のメソッドなので、Boolean.TRUEと書かずにそのまま「TRUE」と書いてますが、見ての通り、Boolean.TRUEかBoolean.FALSEを返しています。こうしてみていると、new Booleanと書かなければ、Booleanは==で比較してもOKなような気もしなくもないです。
Booleanのequalsメソッドはこんなことをしています。
public boolean equals(Object obj) {
if (obj instanceof Boolean) {
return value == ((Boolean)obj).booleanValue();
}
return false;
}
大した処理ではないですが、==の比較の方が若干速くなりそうです。まぁ、そんなわずかの処理の為に、==比較みたいなバグの元になるような記述を入れるのはJavaらしくないですが。
実際にどの程度のメモリ使用量の差があるのだろう
毎回 new Booleanするのと、valueOfを使うのとでは、どの程度のメモリ使用量の差が出るのでしょう。
試しにRuntime.getRuntime.freeMemory()を使用して、使用量を覗いてみましょう。
はい、大変気持ちの良い結果ですね。新しくObjectを生成するわけじゃないので、0になるのは当然と言えば当然なのですが。
試しにRuntime.getRuntime.freeMemory()を使用して、使用量を覗いてみましょう。
Runtime runtime = Runtime.getRuntime();
// new Booleanを1万個ほど生成してみます
Boolean b1[] = new Boolean[10000];
// 追加前のメモリ使用量を持っておきます
long mem1 = runtime.totalMemory() - runtime.freeMemory();
for( int i = 0; i < b1.length; i++ ) {
b1[i] = new Boolean( true );
}
// 生成後のメモリ使用量を取っておきます
long mem2 = runtime.totalMemory() - runtime.freeMemory();
// Autoboxingで1万個ほどBoolean配列を埋めてみます
Boolean b2[] = new Boolean[10000];
// 追加前のメモリ使用量を持っておきます
long mem3 = runtime.totalMemory() - runtime.freeMemory();
for( int i = 0; i < b2.length; i++) {
b2[i] = true;
}
// 生成後のメモリ使用量を取っておきます
long mem4 = runtime.totalMemory() - runtime.freeMemory();
// newでBooleanを1万個生成した際に増加したメモリ量
System.out.println( "使用量 : " + ( mem2 - mem1 ) );
// => 使用量 : 152496
// Autoboxingで1万個のBooleanを埋めた際に増加したメモリ量
System.out.println( "使用量 : " + ( mem4 - mem3 ) );
// => 使用量 : 0
// スコープ内だし大丈夫なはずだけど、念のため、ガベージコレクション封じ的な無駄処理
System.out.println( b1 );
System.out.println( b2 );
さて、結果が出ました。newした場合 | 152496バイト使用 |
Autobxing(valueOfと同義)の場合 | 0バイト使用 |
はい、大変気持ちの良い結果ですね。新しくObjectを生成するわけじゃないので、0になるのは当然と言えば当然なのですが。
総評
というわけで、Booleanの==に関するちょっとしたお話でした。
割とどうでも良い話ですが、何かの閑話休題くらいには使えそうなネタかなぁと思います。
尚、この説明文はMOTHERのプレイ動画を見ながら作成しております。おっ、今、ちょうど歌い始めました。なので誤字等があるかもしれませんが、その時はブログのコメントにご連絡ください。
http://blog.mwsoft.jp/article/30901931.html
割とどうでも良い話ですが、何かの閑話休題くらいには使えそうなネタかなぁと思います。
尚、この説明文はMOTHERのプレイ動画を見ながら作成しております。おっ、今、ちょうど歌い始めました。なので誤字等があるかもしれませんが、その時はブログのコメントにご連絡ください。
http://blog.mwsoft.jp/article/30901931.html