【Java】基本型とボクシングされた基本型

はじめに

Java1.5からボクシングとアンボクシングが導入された。
値を比較しその結果を返す、といったコードを書く際は、ボクシングされた基本型ではなく、基本型を使って値を比較したほうが良い。

基本型とボクシングされた基本型

基本型 ボクシングされた基本型
byte Byte
short Short
int Integer
long long
float Float
double Double
char Character
boolean Boolean

基本型は1とか100といった値のみを持つ。
ボクシングされた基本型は、基本型の値も持つが、nullも持ちうる(オブジェクトなので)。

ボクシング/アンボクシング のさせ方

ボクシングのさせ方とアンボクシングのさせ方はいかの通り。

Integer i = 100;    //基本型からボクシングされた基本型へ(ボクシング)
int val = i;        //ボクシングされた基本型から基本型へ(アンボクシング)

値の比較(実験)

ここでは、冒頭で述べた事柄「ボクシングされた基本型ではなく基本型を使うほうが良い」について述べる。
以下のソースコードではIntegerオブジェクトを2つ受け取り、値が等しければゼロを、等しくなければ1または-1を返すComparator #compareを実装したものである。

import java.util.Comparator;

public class BoxingAndUnboxing implements Comparator<Integer>{

	@Override
	public int compare(Integer na, Integer nb) {
		return na > nb ? 1 : na == nb ? 0 : -1;
	}

}

上記コードのクライアントコードを以下に示す。

public class Main {
	public static void main(String args[]) {
		BoxingAndUnboxing instance = new BoxingAndUnboxing();

		System.out.println(instance.compare(new Integer(10), new Integer(10)));
	}
}

このコードを実行したとき、期待される値はゼロである。なぜなら、同じ「10」を渡しているから。
しかし、このコードを実行したときはゼロではなく、「-1」が返ってくる。
この現象について考察する。

値の比較(考察)

この現象を読み解くカギは、compareメソッド内の「==」である。
compareメソッドでは以下の処理を意図している。

1.   2つのIntegerオブジェクト(naとnb)を受け取る。
2.   値の検証を行う。
2-1. naがnbより大きければ1を返す。
2-2. naとnbが等しければ0を返す。
2-3. そうでなければ-1を返す。

このうち、2-1および2-3は正しく実行される。なぜなら、このときはアンボクシングされて基本型として比較が行われているからである。(2-3に至ってはただ単に-1をリターンするだけ)
問題は2-2のケースであり、このときはIntegerオブジェクトがアンボクシングされて基本型になる「のではなく」、値の同一性の検証が行われる。つまり、2つのオブジェクトは同じモノを参照しているかを検証している。

今回の場合、渡ってきた2つのIntegerオブジェクトは「別モノ」であり、同一性のチェック「na==nb」はfalseとなる。一連のシーケンスをまとめると以下のようになる。

1. na > nb :アンボクシングされて2つの10が検証される。この結果はfalseなので2に進む。
2. na == nb :オブジェクトの同一性が検証される。この結果はfalseなので3に進む。
3. -1をリターンする。

以上を踏まえて、意図したとおりのcompareメソッドを修正すると以下のようになる。
結論から言うと、解決策は、受け取ったIntegerオブジェクト(ボクシングされた基本型)を使って比較するのではなく、て基本型で値を比較する である。

import java.util.Comparator;

public class BoxingAndUnboxing implements Comparator<Integer>{

	@Override
	public int compare(Integer na, Integer nb) {
                int a = na;
                int b = nb;

		return a > b ? 1 : a == b ? 0 : -1;
	}
}

このように修正して事項すると、期待通りゼロが返ってくる。

おわりに

値を比較するときは、ボクシングされた基本型ではなく、基本型の値を使って比較を行うべきであることを、サンプルコードを交えて述べた。
ボクシングされた基本型を使って値を比較すると、「==」で同一性のチェックが行われる。
これを回避し、意図した比較を行わせるためには、ボクシングされた基本型を基本型に変換する必要がある。