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.BYTES=Integer.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_VALUE〜Integer.MAX_VALUEを使用 | 0 | 十進数で9桁まで入るint i = 999999999; | java.lang.Integer |
| long | 符号付き整数 | 64 | -9223372036854775808〜9223372036854775807 普通はLong.MIN_VALUE〜Long.MAX_VALUEを使用 | 0 | 十進数で18桁まで入るlong l = 123456L; | java.lang.Long |
| float | 浮動小数 | 32 | 単精度(有効桁数が最低でも6桁) 使うならFloat.MIN_VALUE〜Float.MAX_VALUE | 0.0 | float f = 123.456F; | java.lang.Float |
| double | 浮動小数 | 64 | 倍精度(有効桁数が最低でも15桁) 使うならDouble.MIN_VALUE〜Double.MAX_VALUE | 0.0 | double d = 123.456; | 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)を比較 → 不一致 |
スーパークラスの変数への代入は、特に問題なく行える。(参照型のワイドニング変換:wideningreference 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でも使える。
ラッパークラスにはコンストラクターがあるが、Java9から非推奨になった。[2021-03-21]
たいていはvalueOfメソッドでインスタンスを生成する。
Java16で、ラッパークラスのコンストラクターは削除対象(将来削除される)になった。
| 変換(左←右) | 式 | 備考 | 更新日 | ||||
|---|---|---|---|---|---|---|---|
| int | String | int i | = | Integer.parseInt(String) | 全角文字の数字も変換できる。 | ||
new Integer(String).intValue() | 変換は出来るが、効率は最悪。 なお、new Integer()はJava9から非推奨。 | 2021-03-21 | |||||
Integer.parseInt(String, 16) | 十六進数を数値に変換する。全角文字も変換できる。 | 2021-09-19 | |||||
HexFormat.fromHexDigits(String) | 十六進数を数値に変換する(Java17以降)。 | 2021-09-19 | |||||
| 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 | |||||
"%d".formatted(int) | Java15以降。 | 2023-09-23 | |||||
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 | |||||
HexFormat.of().toHexDigits(int) | 十六進数(Java17以降)。桁数は8桁固定。 | 2021-09-19 | |||||
HexFormat.of().toHexDigits(long, intketa) | 十六進数(Java17以降)。第2引数で桁数を指定。 | 2021-09-19 | |||||
Integer.toString(int, intn) | n進数に対応。進数nは正の数のみ | ||||||
| String | double | String s | = | Double.toString(double) | // Java18jshell> Double.toString(2e23)$1 ==> "1.9999999999999998E23" // Java19jshell> Double.toString(2e23)$1 ==> "2.0E23" | 2023-09-23 | |
String.format("%e",double) | jshell> String.format("%e", 2e23)$1 ==> "2.000000e+23" | 2023-09-23 | |||||
// Java20jshell> String.format("%.16e", 2e23)$2 ==> "1.9999999999999998e+23" // Java21jshell> String.format("%.16e", 2e23)$2 ==> "2.0000000000000000e+23" | 2023-09-23 | ||||||
String.format("%f",double) | // Java20jshell> String.format("%f", 2e23)$1 ==> "199999999999999980000000.000000" // Java21jshell> String.format("%f", 2e23)$1 ==> "200000000000000000000000.000000" | 2023-09-23 | |||||
"%f".formatted(double) | Java15以降。 | ||||||
| Integer | int | Integer n | = | new Integer(int) | (JDK1.5以降では)-128〜127なら、valueOf()の方が(キャッシュされているので)メモリ使用効率は良い。 Java9で非推奨になった。 | JDK1.5からは直接代入が出来るようになった。 | 2021-03-21 |
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.TRUE・Boolean.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が返るint n =HexFormat.fromHexDigit('a'); // 10が返る(Java17以降)[2021-09-19]数字判断[2007-01-12]
System.out.println(c + ":" +Character.isDigit(c) + "/" +Character.digit(c,16));
0:true/01:true/1a:false/101:true/1…全角数字も数字と判断されるし、数値変換も正しく行われる一:false/-1…さすがに漢数字等は無理(苦笑)壱:false/-1�T:false/-1�@:false/-1字:false/-1
→HexFormat.isHexDigit(c)(Java17以降)[2021-09-19]
プリミティブ型とラッパークラスは別物なのでお互いに直接代入することは出来ないが、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からプリミティブ型への変換は やってくれない。[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;//NullPointerExceptionMap<String, Integer> map = new HashMap<String, Integer>();int i = map.get("zzz");//NullPointerExceptionInteger n = null;n++;//NullPointerExceptionInteger nに対するn++は、実際には「int temp = n.intValue(); temp++; n = Integer.valueOf(temp);」という感じに変換されている。
ループのカウンターとかに使ったら、えらくムダだな…。