S-JIS[2008-05-21/2015-09-23] 変更履歴

Javaの型

Javaの型には、基本的な型(プリミティブ型:PrimitiveType)と参照型(ReferenceType)(および、特殊な空型(null type))が存在する。


プリミティブ型(基本的な型)

コンピューター(CPU)が自然に扱えるのがプリミティブ型[2008-05-21]
booleanとかcharはそうとも言えないが、プログラム言語の基礎的な型として用意されているのだろう。

プリミティブ型の整数(整数型:IntegralType)は2の補数表現で値が保持される。[2008-07-03]
浮動小数点数型(FloatingPointType)はIEEE754規格の数値型。[2008-08-30]
数値(リテラル)の書き方(表現方法)

Javaのプリミティブ型には、対応するラッパークラスがある。[2003-07-06]
プリミティブ型はオブジェクトではないので、(オブジェクトしか扱えない)コレクションに格納する時などにはラッパークラスを使用する。
また、プリミティブ型に属する情報(本来プリミティブ型が主管となるべき情報)(最大値・最小値とか特別な定数など)もラッパークラスに定義されている。
(ちなみにこれらのラッパークラスのほとんどは、共通のNumberクラスから派生している)

各プリミティブ型が何ビットなのかは、JDK1.5以降では該当ラッパークラスのSIZEという定数フィールドで表現されている。[2010-03-23]
JDK1.8ではBYTESという定数フィールドも定義され、何バイトなのかも表現されている。[2014-03-19]
(例えばIntger.SIZEは32ビット、Byte.SIZEは8ビット。したがってintのバイト数はInteger.BYTESInteger.SIZE/Byte.SIZE=4)

基本的なデータ型
データ型 説明 大きさ[bit] 値の範囲
(最小値〜最大値)
デフォルト値 備考 ラッパークラス
void 型無し       [2010-03-23] java.lang.Void
boolean 真偽値 1 true , false false 整数値(0や1)の代入はエラー java.lang.Boolean
char Unicode文字
コードポイント
16 0〜FFFF 0000 char c = 'あ';
全角も半角も可
java.lang.Character
byte 符号付き整数 8 -128〜127 0   java.lang.Byte
short 符号付き整数 16 -32768〜32767 0   java.lang.Short
int 符号付き整数 32 -2147483648〜2147483647
普通はInteger.MIN_VALUEInteger.MAX_VALUEを使用
0 十進数で9桁まで入る
int i = 999999999;
java.lang.Integer
long 符号付き整数 64 -9223372036854775808〜9223372036854775807
普通はLong.MIN_VALUELong.MAX_VALUEを使用
0 十進数で18桁まで入る
long l = 123456L;
java.lang.Long
float 浮動小数 32 単精度(有効桁数が最低でも6桁)
使うならFloat.MIN_VALUEFloat.MAX_VALUE
0.0 float f = 123.456F; java.lang.Float
double 浮動小数 64 倍精度(有効桁数が最低でも15桁)
使うならDouble.MIN_VALUEDouble.MAX_VALUE
0.0 double d = 123.456;
double d = 123.456d;
double d = 1.23456e2;
java.lang.Double
- 任意精度整数   無限?(整数)     java.math.BigInteger
- 任意精度符号付十進数   無限?(小数)     java.math.BigDecimal
- 原子的更新可能boolean     false JDK1.5以降 AtomicBoolean
- 原子的更新可能int     0 AtomicInteger
- 原子的更新可能long     0 AtomicLong

C言語と異なり、unsigned(符号なし)は存在しない。
符号有りか無しかで結果が異なるのは右シフト演算だが、符号有り用と無し用の二種類の演算子が用意されている(演算子によって区別する)。
JDK1.8で符号なし整数を扱うメソッドが追加された

byte→short→int→long、float→double(型の大きさが大きくなる方向)の代入は暗黙に変換される。(プリミティブ型のワイドニング変換:widening primitive conversion)
逆(型の大きさが小さくなる方向)の代入は、明示的に型を指定しないとコンパイルエラーとなる。(プリミティブ型のナローイング変換:narrowing primitive conversion)

	int i = 123;
	double d = i;	//キャスト不要
	double d = 1.2;
	int i = (int)d;	//明示的なキャストが必要

ただし、定数式に関してはコンパイル時に自動的に変換されてエラーにならないことがある。[2008-04-07]

	long l = 123L;
	short s1 = (int)l; 	//コンパイルエラー
	short s2 = (short)l;	//問題なし(通常のキャスト)(long→shortへキャスト)
	short s3 = (int)123L;	//問題なし(定数式が自動変換された)(long→intへキャスト→shortへ自動変換)

符号なし整数

Javaではプリミティブ型の整数は符号付きである。[2014-03-19]
が、JDK1.8で符号なし整数として扱うメソッドがラッパークラスに追加された。

説明 備考
Integer.toUnsignedString(0xffffffff) 4294967295 符号なし整数として文字列化する。 Integer.toString(0xffffffff) -1
Integer.parseUnsignedInt("4294967295") -1 符号なし整数として文字列からintを生成する。 Integer.parseInt("4294967295") NumberFormatException
Integer.parseUnsignedInt("+1") 1 Integer.parseInt("+1") 1
Integer.parseUnsignedInt("-1") NumberFormatException Integer.parseInt("-1") -1
Integer.compareUnsigned(0xffffffff, 0x7fffffff) 1 符号なし整数として比較する。 Integer.compare(0xffffffff, 0x7fffffff) -1
Short.toUnsignedInt((short)0xffff) 65535 符号なし整数としてint化する。 (short)0xffff -1
Integer.toUnsignedLong(0xffffffff) 4294967295 符号なし整数としてlong化する。 (long)0xffffffff -1
Integer.divideUnsigned(0xffffffff, 2) 2147483647 符号なし整数として除算する。 0xffffffff / 2 0
Integer.remainderUnsigned(0xffffffff, 4) 3 符号なし整数として除算した余りを返す。 0xffffffff % 4 -1

Byte・Short・Integer・Longに同様のメソッドが用意されている。

除算以外(加算・減算・乗算)のメソッドが用意されていないのは、普通の演算子を使っても(その型のビット数に収まっている限りは)符号あり・符号なしで相違が無いからだろう。


参照型

プリミティブ型以外は、全て参照型[/2008-05-21]
「参照型」と呼ばれる理由は、実態はC言語でいうところのポインター(すなわち“参照”)だから。
(つまり参照型の変数が保持する値は、オブジェクトの内容そのものではなく、メモリー上に格納されたオブジェクトの先頭アドレスに当たるものプリミティブ型の変数では、値そのものを保持している)。オブジェクトを使うときは、そのアドレスを元にオブジェクトへアクセスする。これを“参照する”と呼んでいる)

クラス(インスタンス・オブジェクト)文字列(String)配列も、全て参照型。
参照型のデフォルト値はnull。

Stringは、ユーザー定義型(クラス)。コンパイルされると、内部ではUnicodeで扱われる。
Stringも参照型なので、デフォルト値は空文字列などではなく、null。

全ての参照型はObjectクラスから派生している(Objectクラスを継承している)。

参照型の変数へ代入する例
時系列 ソース スタック ヒープ 解説
変数var1 変数var2 Objectインスタンス領域
1 Object var1 = null; null - - ローカル変数var1の宣言
2 Object var2 = null; null null - ローカル変数var2の宣言
3 var1 = new Object(); 0xC000 null Objectインスタンス(生成)
先頭アドレスを0xC000とする
インスタンスを生成しvar1に代入
4 var2 = var1; 0xC000 0xC000 Objectインスタンス(0xC000) var1の値をvar2に代入
(参照を渡しているだけなので、同じインスタンスを指す)
5 var1 = null; null 0xC0000 Objectインスタンス(0xC000)  
6 var2 = null; null null Ojbectインスタンス(0xC000)  
7       - 0xC000のインスタンスがどこからも参照されなくなったので
GCによりヒープから削除される。

(参考)プリミティブ型の変数へ代入する例
時系列 ソース スタック ヒープ 解説
変数var1 変数var2  
1 int var1 = 0; 0 - - ローカル変数var1の宣言
2 int var2 = 0; 0 0 - ローカル変数var2の宣言
3 var1 = 123; 123 0 - 値をvar1に代入
4 var2 = var1; 123 123 - var1の値をvar2に代入
5 var1 = 0; 0 123 -  
6 var2 = 0; 0 0 -  
          プリミティブ型はヒープとは何ら関係ない。
したがってGCとも無関係。

参照型で比較する例
時系列 ソース スタック ヒープ 解説
変数var1 変数var2 1つ目 2つ目
1 String var1 = new String("abc"); 0xC000 - String生成
アドレスを0xC000とする
- ローカル変数var1の宣言
2 String var2 = new String("abc"); 0xC000 0xC100 Stringインスタンス(0xC000:"abc") String生成
アドレスを0xC100とする
ローカル変数var2の宣言
3 if (var1.equals(var2)) 〜 0xC000 0xC100 Stringインスタンス(0xC000:"abc") Stringインスタンス(0xC100:"abc") var1の参照先(0xC000の中身)とvar2の参照先(0xC100の中身)を比較
→ 一致
4 if (var1 == var2) 〜 0xC000 0xC100 Stringインスタンス(0xC000:"abc") Stringインスタンス(0xC100:"abc") var1の値(0xC000)とvar2の値(0xC100)を比較
→ 不一致

スーパークラスの変数への代入は、特に問題なく行える。(参照型のワイドニング変換:widening reference conversion[2008-08-30]
逆の代入(いわゆるダウンキャスト)は明示的なキャストが必要。(参照型のナローイング変換:narrowing reference conversion)

ナローイング変換が正しく行えることを事前チェックする目的でinstanceofが使われる。

class C1 {
}

class C2 extends C1 {
}
	C1 c = new C2();	//ワイドニング変換

	if (c instanceof C2) {
		C2 d = (C2)c; //ナローイング変換
	}

変数の初期化(デフォルト値)

Javaでは、ローカル変数を初期化しないで使おうとする(初期化されずに使われる可能性がある)と、コンパイルエラーになる(基本的なデータ型であっても)。[2008-05-21]
C言語ではローカル変数を初期化しないと値が不定となる為、初期化しないのはご法度だった)
ローカル変数無初期化の勧め(?)

しかし、クラスのフィールド(メンバー変数)で初期値を指定していない場合newで作った配列で 各要素を明示的に初期化していない場合デフォルト値が入れられる。
デフォルト値は それぞれの型によって定められている。(booleanならfalse、その他のプリミティブ型は0、参照型はnull)


型変換

オブジェクト(参照型)からStringへ変換するには、toString()メソッドがよく使われる。[2008-05-21]
全てのクラスの親であるObjectクラスにはtoString()が定義されており、継承したサブクラスではそれをオーバーライドして文字列(String)への独自の変換処理を行う/行ってよい/行うのがよい。

String等から他クラス(自作クラス)への変換は、ラッパークラス列挙型(enum)に倣ってvalueOf()を実装する…のがいいかなぁ。[/2009-12-31]
クラスによってはparse()とかdecode()というのもあるけど。

プリミティブ型に関する操作は、たいてい対応するラッパークラスに揃っている。[2007-06-30]
ちなみにこれらのラッパークラスのほとんどは 共通のNumberクラスを継承しているので、例えばintへ変換するintValue()はIntegerでもLongでもDoubleでもByteでも使える。

代表的な型変換
変換(左←右) 備考 更新日
int String int i = Integer.parseInt(String)    
new Integer(String).intValue() 変換は出来るが、効率は最悪 2007-12-20
Integer String Integer n = Integer.decode(String) 「0x」「#」から始まると十六進数として認識してくれる。 2007-12-29
String int String s = Integer.toString(int)    
String#valueOf(int) 内部ではInteger#toString(int, 10)を呼んでいる。  
"" + int JavaScriptでは常套手段だが、JavaではStringBuilderが余計に作られるのでいまいち。 2008-05-22
String.format("%d", int) JDK1.5以降。0埋めや桁数指定("%04d")が出来る。 2008-05-21
Integer.toBinaryString(int) 二進数  
Integer.toOctalString(int) 八進数  
String.format("%o", int) 八進数(JDK1.5以降)。0埋めや桁数指定("%04o")が出来る。 2008-05-21
Integer.toHexString(int) 十六進数。0埋めはString s = Integer.toHexString(b);if (b.length < 2) s = "0" + s;とか 2008-07-05
String.format("%x", int) 十六進数(JDK1.5以降)。0埋めや桁数指定("%04x")が出来る。 2008-05-21
Integer.toString(int, int n) n進数に対応。進数nは正の数のみ  
Integer int Integer n = new Integer(int) (JDK1.5以降では)-128〜127なら、valueOf()の方が(キャッシュされているので)メモリ使用効率は良い。 JDK1.5からは直接代入が出来るようになった。 2007-12-29
Integer.valueOf(int) JDK1.5以降で使用可能。 2007-05-02
int Integer int i = IntegerObj.intValue()    
boolean String boolean b = Boolean.parseBoolean(String) JDK1.5以降 2009-12-31
Boolean String Boolean b = Boolean.valueOf(String)   2009-12-31
Boolean boolean Boolean b = Boolean.valueOf(boolean) JDK1.4以降(定数ならBoolean.TRUEBoolean.FALSEを使うのがいい) 2009-12-31
Date String       日付(Date)⇔文字列(String)の変換  
String Date        

※Boolean.getBoolean()やInteger.getInteger()は、変換用ではなく、システムプロパティーの取得用。[2009-12-31]

十六進数文字⇔数値変換 [2007-01-12]

	char c = Character.forDigit(10, 16); //'a'が返る
	int  n = Character.digit('a', 16);	//10が返る

数字判断 [2007-01-12]

	System.out.println(c + ":" + Character.isDigit(c) + "/" + Character.digit(c,16));
0:true/0
1:true/1
a:false/10
1:true/1		…全角数字も数字と判断されるし、数値変換も正しく行われる
一:false/-1	…さすがに漢数字等は無理(苦笑)
壱:false/-1
T:false/-1
@:false/-1
字:false/-1

半角カタカナ⇔全角カタカナ⇔全角ひらがな変換


自動ボクシング

プリミティブ型ラッパークラスは別物なのでお互いに直接代入することは出来ないが、JDK1.5からは出来るようになった。[2007-05-02]
これを自動ボクシング(オートボクシング:AutoBoxing)と呼ぶ。
→Sunのオートボクシング

	Integer i = 123;	//オートボクシング(ボクシング変換:boxing conversion)
	int j = i;	//オートアンボクシング(アンボクシング変換:unboxing conversion)

(コンパイルする際にはソースのレベルを1.5以上にする必要がある)

コンパイルしたものを逆コンパイルして見ると、ただ単に変換メソッドに置き換えられているだけ…。

	Integer i = Integer.valueOf(123);
	int j = i.intValue();

なので、コーディング上は便利だけど、実行効率的には気をつけた方が良さげ。

プログラミング上も、オーバーロードされているメソッドで引数の違いがintとObjectだった場合とかは、どちらのメソッドが呼ばれるか気をつけなきゃいけないだろうな。

	Integer i = 123;
	System.out.println(i);	//引数がObject型のprintln()が呼ばれる

Objectクラスとの自動ボクシング

ちなみに、プリミティブ型からObjectクラスへのボクシングも勝手にやってくれるが、Objectからプリミティブ型への変換は やってくれない。[2007-05-10]

	Object obj = 123;	//OK(実体はIntegerのインスタンス)
	int i = obj;	//コンパイルエラー

intへ変換するintValue()とかlongへ変換するlongValue()とかは、実は“IntegerやLongの親クラスであるNumberクラス”のメソッドなので、「int i = ((Number)o).intValue();」とかに変換してコンパイルすることは出来るはず。
だが、実体がNumberの派生クラスでない場合は実行時エラーになる(実行してみるまで分からない)ので、コンパイルエラーにしておくのが無難なのかな。
(nullだと実行時にNullPointerExceptionが起きるらしいが)

Integerであることが分かっているなら、キャストしておけばコンパイルエラーは消せる。[2008-07-21]

	Object obj = 123;
	int i = (Integer)obj;	//OK
//×	int i = (Number)obj;	//Numberからintへ変換できないというコンパイルエラー
//×	long l = (Long)obj;	//コンパイルエラーにはならないが、実行時にClassCastException(Integer→Longは×)

使用上の注意

プリミティブ同士なら==演算子で比較するが、オートボクシングで変換されればラッパークラスというオブジェクト(参照型)になるので、==で比較するなんて、もっての他。[2008-05-21]

	public static void main(String[] args) {
		{
			System.out.print(127);
			Integer i1 = 127;
			Integer i2 = 127;
			if (i1 == i2) {
				System.out.println("は等しい");
			} else {
				System.out.println("は異なる");
			}
		}
		{
			System.out.print(128);
			Integer i1 = 128;
			Integer i2 = 128;
			if (i1 == i2) {
				System.out.println("は等しい");
			} else {
				System.out.println("は異なる");
			}
		}
	}

実行結果:

127は等しい
128は異なる

何で結果が違うかというと、intからIntegerへは「new Integer()」でなく「Integer.valueOf()」が使われるから。
これは(現状では)-128〜127の範囲ではキャッシュされたIntegerを返すようになっているので、その範囲なら同一のインスタンスとなる。だから==で比較しても等しくなる。
しかしその範囲外だとnewで作るので、==では一致しない

そういうわけで現状は-128〜127の範囲なら大丈夫かもしれないが、将来バージョンで変わっても不思議は無いので、==を使うべきではない。
というかクラス(Integer)が明示的に現れているんだから、そもそも==で比較しようとすんなやって話。

Java言語仕様第3版5.1.7章の中で「-128〜127」と書かれているので、その範囲が狭くなることは無いと思うが。[2008-08-30]


逆のオートアンボクシングでは、ラッパークラス側がnullにならないように注意。[2008-05-21]
nullだと実行時にNullPointerExceptionが発生してしてしまう。

	Integer n = null;
	int i = n;	//NullPointerException
	Map<String, Integer> map = new HashMap<String, Integer>();
	int i = map.get("zzz");	//NullPointerException
	Integer n = null;
	n++;	//NullPointerException

Integer nに対するn++は、実際には「int temp = n.intValue(); temp++; n = Integer.valueOf(temp);」という感じに変換されている。
ループのカウンターとかに使ったら、えらくムダだな…。


Java目次へ戻る / 新機能へ戻る / 技術メモへ戻る
メールの送信先:ひしだま