〜java.lang.Integer他〜
手始めにラッパークラスを見ていきましょう。メソッド名など必要になったらAPIドキュメントで調べれば結構です。「へぇこんなのがあるんだ」と読み進めてください。

基本データ型は次の8種類がありました。(
→基礎編 第1章)それぞれに対応して、右のようなクラス型があります。これを
ラッパークラス(wrapper class)といいます。
基本データ型 ラッパークラス
boolean
Boolean
char
Character
byte
Byte
short
Short
int
Integer
long
Long
float
Float
double
Double
ほとんどが先頭1文字を大文字にしただけですが、CharacterとIntegerはフルネームになっているので気をつけましょう。ここからは主にintとIntegerの対比を見ていきます。これがわかれば他の型も大丈夫、頑張りましょう。
下の図は、基本データ型のintと、ラッパークラスのIntegerについて、変数の宣言と値の代入の比較をしています。
まずint型の場合は、xに直接整数値5が入るのでしたね。またxの中身は「x=10;」のように変更できます。
一方Integer型の変数yはクラス型なので、一々newでインスタンスを生成しなければなりません。このときコンストラクタの引数にint型の値を与えてやります。図の右上にあるように、yのインスタンス中のインスタンス変数に5が入ります。ところがこのインスタンス変数は実はprivateの上、変更するメソッドもありません。(Integerのドキュメントを見てもフィールド一覧の中にありません。)つまり赤い箱は一旦コンストラクタで値が与えられると変更できないのです。もしyの持つ整数値を10にしたければ、右下のように新たにインスタンスを生成しなければなりません。
さてはてなんでこんな面倒なラッパークラスがあるのでしょうか?いくつか理由があります。見ていきましょう。
「クラス型の変数は
nullが保持できる」ということを利用して例を考えて見ましょう。
何か整数値をとるデータを毎時間測っていることにします。時々測り忘れてしまってデータが抜けているというお粗末振り。さてこんなときint型の場合は、変数に-999とか-99999など特別な値を入れて区別するでしょう。データ出力のメソッドはこんな具合。
public void printDataInt(int x) {
if(x == -999) {
System.out.println("忘れた");
} else {
System.out.println(x);
}
}
でもそのデータが-999や-99999を実際とる場合も無きにしも非ず、というときはまずいですね。測り忘れなのか、本当にその値のデータなのかわからなくなってしまいます。また-999とか-99999を周知徹底しておかないと、そのままデータとして出力してしまうメソッドを作る人がいるかもしれません。
public void printDataInt(int x) {
System.out.println(x);
}
一方Integer型の変数にはnullを代入できます。「null→測り忘れ」の図式ができすっきりします。
public void printDataInteger(Integer x) {
if(x == null) {
System.out.println("忘れた");
} else {
System.out.println(x.intValue());
}
}
最後の
intValueは、インスタンス変数に記憶されたint型の値を取り出してくれます。(JDK5.0では、int⇔Integerの変換が簡単にできるようになりました。)もし万が一メソッド作成者がnullのチェックを忘れれば、仮引数xにnullが渡されたとき、NullPointerExceptionの例外が発生して、「おおそうだ、測り忘れの場合もあったんだ!」と思い出させてくれ、メソッドに上のようなif文を追加するでしょう。
intValueの他にlong型で取り出したければ
longValue、double型で取り出したければ
doubleValueなどのメソッドもあります。
他の例として、Boolean型の場合、true、false、どちらでもない、の三つのデータを表現できてまた便利です。「どちらでもない」は「まだ決めかねてる」とか「回答なし」などでもいいですね、もちろんnullで表します。
まあ測り忘れはないことにして、たくさんデータが集まったので、これをいろいろ分析することにしました。そのためにint型の配列(
→基礎編 第7章)を使います。図が大変なので、たくさんといっても3個にしておきます。
int[] a = new int[3];
a[0] = 5;
a[1] = 3;
a[2] = -7;
では4個目のデータを入れようとするとどうなるでしょうか?
a[3] = 10;
そう、ArrayIndexOutOfBoundsExceptionという長ったらしい名前の例外が発生します。最初からデータ数がわかっていれば問題ないのですが、追加追加でドンドン増える可能性のある場合、最初に相当大きい配列を確保しておかなければならず、メモリの無駄遣いになります。
java.util.
ArrayListを使うと、最初は控えめにエリアを確保しておいても、足りなくなった時点で自動的に追加してくれるので便利です。伸び縮みできる配列と考えてください。この場合、int型のデータをそのまま扱うことはできず、Integerを使います。(細かい文法は抜きで見てください。)
ArrayList b = new ArrayList(3);
b.add(new Integer(5));
b.add(new Integer(3));
b.add(new Integer(-7));
次のように続けて4個目のデータを入れようとしても例外は発生しません。
b.add(new Integer(10));
あらかじめデータ数がはっきりしないときは便利ですね。他にもパッケージjava.utilにはコレクションAPIと呼ばれる、たくさんのデータを扱う便利な機能がいくつもあります。いろんなデータを扱えるようにするため、これらはオブジェクトの参照を記憶します。だからint型はラッパークラスのInteger型にしなければならなかったのですね。コレクションAPIはまた後ほど詳しくやろうと思っています。
クラスIntegerのAPIを見ると、たくさんのメソッドがあります。主にstaticの付いたクラスメソッドで、int型のデータを扱うときに役立つクラスです。四つのグループに分けてみました。
@int→String
「to何とかString」の形で、何とかの部分は、引数のintを何進数で表すかによってちがってきます。例えば「
toHexString」であれば16進数にします。ただの「
toString」は一番身近な10進数です。
String s = Integer.toHexString(123) + " " + Integer.toString(123);
System.out.println(s);
System.out.println(123);
出力は次のようになります
7b 123
123
1行目は123の16進表示と10進表示です。最後の出力
System.out.println(123);
は
System.out.println(Integer.toString(123));
と同じになります。
AString→int
「parseInt」です。わりと使うかもしれません。下は画面から入力された年齢をint型に変換しています。もし整数値として正しくない文字列(12sとか3.5など)が実引数に指定されれば、例外NumberFormatExceptionが投げられます。
String inputString;
ここでinputStringに画面から入力
int age = Integer.parseInt(inputString);
BString→Integer
「valueOf」が二つあります。
CInteger→基本データ型
「何とかValue」の形で、何とかの部分は、変換先の型名になります。intに変換するのであればintValueになります。
@〜Bはクラスメソッドなので、クラスIntegerになくてもいいのですが、やはりintやIntegerに関するメソッドなので、Integer内で定義されています。
この他、int型で表せる最大値MAX_VALUE、最小値MIN_VALUEもあります。
System.out.println(Integer.MAX_VALUE + " " + Integer.MIN_VALUE);
|
で
2147483647 -2147483648
が出力されます。これは27−1と−27です。結構大きな整数値まで入れられますが、これでも足りない場合は、long、まだまだという方は、java.math.BigIntegerというクラスがあります。調べてみてください。
double型に対応するラッパークラスDoubleについても、少し見ていきましょう。Integerと同様MAX_VALUEとMIN_VALUEがあります。
System.out.println(Double.MAX_VALUE + " " + Double.MIN_VALUE);
|
で
1.7976931348623157E308 4.9E-324
と出力されます。気をつけてほしいのはMIN_VALUEの方です。これは0に一番近いdoubleの値です。4.9×10−324ですからかなり小さいですね。
本来実数値は連続しているので、どんな小さな値でも、それをまた半分にすれば、もっと小さな値が得られます。でもコンピュータはご承知の通り、0と1で何でも表すので、浮動小数点の値は不連続です。小さな小さな階段状になっていると考えると、その一段分がDouble.MIN_VALUEになります。当たり前のことですが、数値計算ではこのことを頭に入れておかないと、思わぬ誤差に振り回されます。
なおdouble型の負の最小値は-Double.MAX_VALUEになります。
次はdouble型の除算です。ゼロで割っていますが、例外は発生せず、zには正の無限大の値、Double.POSITIVE_INFINITYが入ります。負の無限大はNEGATIVE_INFINITYですが、クラスメソッドisInfiniteで無限大かどうかを調べられます。またxも0の場合、zは非数値のNaNになります。これはメソッドisNaNで調べます。気をつけてほしいのは、
z == Double.NaN
としてはならないこと。必ずisNaNで調べましょう。
double x = 120, y = 0, z;
z = x / y;
if(Double.isInfinite(z)) {
System.out.println("ゼロ割り");
} else if(Double.isNaN(z)) {
System.out.println("ゼロ/ゼロ");
} else {
System.out.println(z);
}
|
おまけ
double型の0.1のビット列がほしかったので、次で出力しました。ラッパークラスにはいろいろ便利なクラスメソッドがあるんですねぇ。(注意:頭の0は出ません。)
System.out.println(Long.toBinaryString(Double.doubleToLongBits(0.1)));
|
おまけのおまけ
小学校の算数で「0.1を10こ集めた数はなんですか?」という難問中の「0.1」と、Javaのプログラム中の「0.1」は同じ値ではありません。double型の値はIEEE754と呼ばれる決まりに従って表されます。2進数に変換するので、実は0.1は循環小数になってしまいます。これを8バイトに押し込めるのですから仕方ありません。上の問題を「ハイッ!1です。」と素直に答えられた昔が懐かしい...(
→参考 合格Java(基礎編) 1.Javaの基礎 問題4)
Copyright (c) 2004-2005 Nagi Imai All Rights Reserved..