Javaについて徹底解説!

Javaの整数型intを一から解説 値の範囲、他の型・Stringとの変換も

大石 英人

大石 英人

開発エンジニア/Java20年/Java GOLD/リーダー/ボールド歴2年

Javaのintは、プリミティブ型の一つで、32ビットの範囲で整数を表現できます。intでは、およそ±215千万の値を表現できます。

Javaで整数を扱う時は、普通はintを使います。intを使わないJavaのプログラムは考えられないほど、ごく普通に使われます。ですので、intを使うことは、Javaプログラミングの基本だとも言えるでしょう。

だからこそ、intの特徴や使い方をしっかり知っているということは、Javaでプログラミングをする上でもはっきりとした足場や土台があるということです。それくらいJavaプログラミングではintは重要です。

この記事ではintについて、そもそもintとはどういうものか、intはどうやって使うのか、気を付けたい所などを初心者向けにお伝えします。

※この記事のサンプルは、Java 11の環境で動作確認しています


1.intはJavaの整数型のスタンダード

intはJavaで最もよく使う整数のデータ型で、プリミティブ型(primitive、基本データ型)と呼ばれるものの一つです。

一つのintのサイズは32ビット(4バイト)です。intという名前の由来は、英語のinteger(整数)の先頭部分です。

intを他のプリミティブ型と簡単に比較すると、以下のとおりです。

データ型値の種類ビット数表現できる値の範囲接尾語備考
boolean真偽値1ビットtrue/falseのどちらか
byte整数8ビット(1バイト)-128~127
short整数16ビット(2バイト)-32,768~32,767
char文字16ビット(2バイト)0~65,535Unicode文字、\u0000\uffff
int整数32ビット(4バイト)-2,147,483,648~
2,147,483,647
±2147百万、Unicodeコードポイント
long整数64ビット(8バイト)-9,223,372,036,854,775,808~
9,223,372,036,854,775,807
Lまたはl±922
float浮動小数点32ビット(4バイト)±3.40282347E+38~ 1.40239846E-45Fまたはf単精度
±3.4×1038乗~約±1.4×10-45
double浮動小数点64ビット(8バイト)±1.79769313486231570E+308~±4.94065645841246544E-324Dまたはd

倍精度
±1.8×10308乗~約±4.9×10-324

1-1.intは1ずつ増減し、プラスマイナスがある整数型

整数型とは、プログラム上で数字を表現するデータ型の一つです。整数は-10123…のように、ちょうど1ずつ増減する数値で、小数点は含みません。小数点の数値を含められるデータ型は、浮動小数点型という別のものです。

Javaではプラスの整数、マイナスの整数の両方をintだけで表現します。他のプログラミング言語では、符号のないデータ型がありますが(unsigned intなど)Javaintは符号があるデータ型です。

1-2.intは±21億ぐらいまでの整数を表現できる

Javaのintでは、±215千万くらいまでの整数を表現できます。正確に書けば、-2,147,483,6482,147,483,647の範囲の整数です。

32ビットの2進数で表現できるパターンは約43億とおりなので、少ないと思われたかもしれません。でも、Javaでのintはもっとも大きな桁の1ビットをプラスマイナスの符号に使いますので、数値に使えるサイズは31ビット(21)になるのです。

intの32ビットのビットパターンと、実際の数字は以下のように対応します。

8バイト目7~2バイト目1バイト目10進数表現備考
0000全て000000すべてのビットが0
0000全て000011
0000全て000102
0111全て111102,147,483,646
0111全て111112,147,483,647Integer.MAX_VALUE
1000全て00000-2,147,483,648Integer.MIN_VALUE
1000全て00001-2,147,483,647
1111全て11110-2
1111全て11111-1すべてのビットが1+1すると0に戻る

intは0から始まって1ずつ大きくなり、32ビット目が0かつ131ビット目が全て1が最も大きな正の整数です。そこから、次の32ビット目が1かつ031ビット目が全て0が最も小さな負の整数で、1ずつ大きくなっていき、全てのビットが1になると-1です。

1-3.Javaのintはいつでもどこでも32ビット

Javaではどの環境でも、昔も今もこれからも、int32ビットです。「それが何なの? 当然でしょ?」と思われたかもしれませんが、実はこれがJavaのいいところの一つです。

他のプログラミング言語では、このような基本的なデータの大きさにも、環境による違いがあったりします。例えば、昔のC言語ではint16ビットでしたが、今では大体32ビットです。さらに、今ではint16/int32/int64などがあり、きちんと理解して使うにはなかなか複雑です。

ですが、Javaでは最初からint32ビットです。これは今後もずっと変わりません。どんなJavaの環境でも同じですし、プログラムの作り直しはいらないのです。覚えやすさと言う意味でもいいことですよね。


2.intの基本的な使い方

ここでは、intの使い方のサンプルをお伝えします。そして、intを使う上では注意すべきことがいくつかありますので、それらも順番にお伝えします。

2-1.intの宣言の仕方、初期値

2-1-1.intの変数・配列の宣言、初期値の指定

intは型の一つですから、以下のように変数や配列変数の型として使えます。もちろんメソッドの引数や、戻り値としても使えます。

// int型の変数の宣言と、初期値の代入
int i = 65535;

// int型の配列の宣言と、各インデックスへの値の代入
int[] iarr = new int[5];
iarr[0] = 11;
iarr[1] = 12;
iarr[2] = 13;
iarr[3] = 14;
iarr[4] = 15;

2-1-2.intのリテラルの書き方

小数点の無い数字をプログラム上にそのまま書くと、Javaのプログラム上ではintとして認識されます。このような書き方をリテラル(文字どおりの、という意味)と呼びます。

intのリテラルを書く時は、接頭語をつけなければ10進数です。Java 11の時点では10進数の他に以下の書き方ができます。さらに、“_”で桁区切りが出来るようにもなっています。

  • 2進数(“0b”で始まる、Java 7から)
  • 8進数(“0”で始まる)
  • 10進数(接頭語なし)
  • 16進数(“0x”で始まる)
int i1 = 123456789; // 10進数
int i2 = 0b1010101; // 2進数
int i3 = 012345670; // 8進数
int i4 = 0x123ABCDE; // 16進数
int i5 = 123_456_789; // 桁区切り(3桁ごと)
int i6 = 0b1111_1010_0101; // 桁区切り(4ビットごと)

2-1-3.intのフィールド、配列の初期値は0

フィールドとしてint型の変数を使ったり、int型の配列を使う場合は、未初期化だと0になります。

class IntTest {
	int i; // intをフィールドとして宣言したが、初期値は未設定

	public static void main(String[] args) {
		IntTest intTest = new IntTest();
		System.out.println(intTest.i); // → 0、変数宣言時に初期化されていないのでデフォルト値が設定される

		int[] array = new int[5];
		System.out.println(array[0]); // → 0、newした時点で配列全体が0で初期化される
	}
}

2-2.intを使った四則演算

intを使った四則演算(加減乗除)には、四則演算用の算術演算子、つまり+-*/を使います。余りを求めるなら%です。ですので、ごく直感的に計算できるかと思います。

ただし、計算結果で小数点が出た場合、intの変数へ代入すると、小数点以下の値は切り捨てされます。これは整数型のプリミティブに共通する動きです。

int i = 10;
int j = 3;

int plus = i + j;
int minus = i - j;
int multiply = i * j;
int divide = i / j;
int surplus = i % j;

System.out.println(plus); // → 13
System.out.println(minus); // → 7
System.out.println(multiply); // → 300
System.out.println(divide); // → 3(計算上は10 / 3 = 3.333…だが、小数点以下が切り捨てられて0になる)
System.out.println(surplus); // → 1

2-1-1.大きな整数を計算するなら、符号の変化に要注意!!

絶対値が大きな値を使う場合は、符号の変化に注意しましょう。

intに数値を加減算して、プラス側の最大値を超えるとマイナス側の最大値になり、マイナス側の最小値よりも小さくなるとプラス側の最大値になります。つまり、プラスマイナスがひっくり返るタイミングがあり、オーバーフローと呼ばれます。

int i1 = Integer.MAX_VALUE;
int i2 = i1 + 1;
int i3 = i1 + 2;
System.out.println(i1); // → 2147483647
System.out.println(i2); // → -2147483648
System.out.println(i3); // → -2147483647

int i4 = Integer.MIN_VALUE;
int i5 = i4 - 1;
int i6 = i4 - 2;
System.out.println(i4); // → -2147483648
System.out.println(i5); // → 2147483647
System.out.println(i6); // → 2147483646

これは、二進数で言うと 0111111111111111111111111111111 1000000000000000000000000000000 の間でプラスマイナスが変わるということです。前者がInteger.MAX_VALUE、後者がInteger.MIN_VALUEです。これを細かく言えば、Javaでは2の補数でマイナスの数値を表現しているから、ということです。

問題になる例として、業務システムで金額項目をintにして、その金額同士を足し合わせると予期せぬ数値になることがあります。例えば、15億と10億を足しても25億にはならないのです。計算する数値の桁数が大きいなら、もっと大きな数が扱えるlongdoubleにしておくといいでしょう。

int i1 = 1_000_000_000; // 10億
int i2 = 1_500_000_000; // 15億
int sum = i1 + i2;
System.out.println(sum); // → -1794967296! 25億にはならない!

2-3.intでのビット演算

intはビット演算にも使えます。業務向けのプログラムではビット演算はほとんど使いませんが、科学技術計算など処理速度が要求されるプログラムでは、ビット演算により計算をすることもあります。特に、掛け算や割り算をシフトで代用するのが代表的です。

なお、C言語の名残があるプログラムだと、処理のオプションをビットパターンで指定することがあったりします。また、プログラムの仕様として特定ビットの値が1かどうかを調べることもありますので、ビット演算のやり方は覚えておいても損はありません。

以下では、Javaintを使ったビット演算のやり方だけ、簡単に示しておきます。

int i1 = 0b101;
int i2 = 0b010;

// 論理和(or) |
int or = i1 | i2;
System.out.println(Integer.toBinaryString(or)); // → 111
// 論理積(and) &
int and = i1 & i2;
System.out.println(Integer.toBinaryString(and)); // → 0

i1 = 0b1100;
i2 = 0b1010;

// 排他的論理和(xor) ^
int xor = i1 ^ i2;
System.out.println(Integer.toBinaryString(xor)); // → 110

i1 = 0xfffffffe;

// 論理否定(not) ~
int not = ~i1;
System.out.println(Integer.toBinaryString(not)); // → 1

i1 = 0b11111111111111111111111111111111;

// 左シフト <<
int ls = i1 << 1;
System.out.println(Integer.toBinaryString(ls)); // → 11111111111111111111111111111110
// 右シフト(算術シフト) >>
int rs1 = i1 >> 1;
System.out.println(Integer.toBinaryString(rs1)); // → 11111111111111111111111111111111
// 右シフト(符号なし、論理シフト) >>>
int rs2 = i1 >>> 1;
System.out.println(Integer.toBinaryString(rs2)); // → 1111111111111111111111111111111

2-4.intと他のプリミティブ型との変換

Javaでは数値型のプリミティブ型として、intとビット数が違う整数(byte/short/char/long)と、小数点が扱えるもの(float/double)があります。それらとの変換や演算の時には注意することがいくつかあります。

2-4-1.整数のプリミティブ型との変換

ビット数が違うものとの変換では、ビット数が小さい型大きい型への変換は問題ありません。intなら、byte/short/charからの変換です。ビット数が小さい型の値は、ビット数が大きい方の型で全て表現できるからです。

でも、ビット数が大きい型小さい型へ変換する場合は、大きい型の上位ビットにある情報が消えてしまいます。intならlongからの変換が要注意です。

また、ビット数が大きい型から小さい型に変換する際は、明示的なキャストが必要です。これは、値が失われる可能性がある操作をしているのだと、プログラマに意識させるためです。

ビット数が小さい型から大きな型へはキャストはいりませんが、ここでも暗黙的キャストというものが行われています。

byte b = -128;
short s = -32768;
char c = 65535;
long l = -9223372036854775808L; // 0b100000...のように、1の後ろに0が63個続く

int i1 = b;
int i2 = s;
int i3 = c;
int i4 = (int)l; // 64ビットのlongから32ビットのintへの変換にはキャストが必要

System.out.println(i1); // → -128
System.out.println(i2); // → -32768
System.out.println(i3); // → -65535
System.out.println(i4); // → 0! longの33~64ビット目がなくなり、全て0になったため

逆に、intから変換する場合は、それぞれのプリミティブのビット数までの値になります。longならintよりも大きいので、値をそのまま保持できます。

下記の例だと、byte/short/charはそれぞれのビットが全て1になります。ビットが全て1だと、整数型なら共通で-1です。

int i = 0b11111111111111111; // 1~17ビット目まで1とする。そこから上は0
System.out.println(i); // → 131071

byte b = (byte)i;
short s = (short)i;
char c = (char)i;
long l = i; // ビット数がより多いlongへならキャストはしなくてもいい

System.out.println(b); // → -1、0b11111111
System.out.println(s); // → -1、0b1111111111111111
System.out.println((int)c); // → 65535、0b1111111111111111
System.out.println(l); // → 131071、longならカバーできる

2-4-2.浮動小数点のプリミティブ型との変換

浮動小数点のプリミティブ(float/double)intの間で変換をすると、浮動小数点数にはあった小数部が失われてしまいます。また、浮動小数点はintよりもはるかに桁が大きな数値を表現できますが、そういう大きな桁の情報もなくなってしまいます。

float/doubleからintに変換する際は、値が失われる可能性がある操作なので、明示的なキャストが必要です。逆に、intからfloat/doubleへの変換にはキャストは不要です。

double d1 = 1.23;
double d2 = Double.MAX_VALUE; // 1.7976931348623157E308、約1.8×10の308乗!!

int i1 = (int)d1;
int i2 = (int)d2;

System.out.println(i1); // → 1
System.out.println(i2); // → 2147483647、約2.15×10の9乗
int i = Integer.MAX_VALUE;
System.out.println(i); // → 2147483648

float f = i;
double d = i;

System.out.println(f); // → 2.14748365E9
System.out.println(d); // → 2.147483647E9

2-5.intとStringとの変換

Stringもintと並んでJavaでは重要なクラスです。Stringintにすること、またintStringにすることは、プログラムでは日常茶飯事です。ここではその方法をお伝えします。

2-5-1.String→intの変換

ファイルから読み込んだ文字列や、引数で受け取った文字列からintを作りたい時があります。そういう時はInteger.parseIntを使いましょう。文字列をintに変換してくれます。intと解釈できない文字列の場合はNumberFormatExceptionthrowされますのでご注意を。

String intStr = "12345";
int i = Integer.parseInt(intStr);
System.out.println(i); // → 12345

2-5-2.int→Stringの変換

逆に、intStringにしたい時があります。簡単に行うなら、Integer.toString(int)か、String.valueOf(int)を使いましょう。ちなみに、どちらを使っても結果は同じです。

int i = 12345;
String intStr = String.valueOf(i);
System.out.println(intStr); // → "12345"

また、int3桁区切りなどでフォーマットしたり、0埋めをしたい場合もあるでしょう。その場合は、java.text.DecimalFormatString.formatを使います。それぞれの書式の詳細は、Javadocを参照してください。

int i = 1234567;

DecimalFormat df1 = new DecimalFormat("#,###");
DecimalFormat df2 = new DecimalFormat("000,000,000");

String intStr1 = df1.format(i);
String intStr2 = df2.format(i);

System.out.println(intStr1); // → 1,234,567
System.out.println(intStr2); // → 001,234,567
int i = 1234567;

String intStr1 = String.format("%,d", i);
String intStr2 = String.format("%,011d", i);

System.out.println(intStr1); // → 1,234,567
System.out.println(intStr2); // → 001,234,567

java.text.DecimalFormat

https://docs.oracle.com/javase/jp/11/docs/api/java.base/java/text/DecimalFormat.html

 

java.lang.String.format

https://docs.oracle.com/javase/jp/11/docs/api/java.base/java/lang/String.html#format(java.lang.String,java.lang.Object…)


3.intとInteger

Javaでは32ビットの整数を表現するために、intIntegerの二つの方法があります。Javaプログラミングの初心者は、なぜ同じ整数の表し方が二つあるのか混乱すると思います。

この章ではその理由と、intIntegerの使い分けの方針などをお伝えします。

3-1.二種類の表現方法は性能確保のため

Javaではプリミティブ型のintと、クラスのIntegerは別物です。C#などではこういう区別がないのに、なぜJavaではあるのか。これは、Javaが生まれた当時にプログラムの実行速度を確保するためでした。

Javaは1995年に登場したプログラミング言語です。当時のCPUのクロック周波数は今とは桁が違い、一般向けのCPUでようやく100MHzを超えたくらい。メモリの量も全体で数MB~数10MBと非常に乏しかったものです。

intは32ビットの数字そのものなので、楽に速く扱えます。しかし、intをクラスとすると、一つのintの数値を表すのに32ビットよりもずっと多くのメモリを使います。簡単な計算をするにも、処理上では余分なオーバーヘッドが発生します。

3-2.クラスのIntegerならnullを表現できる

JavaでIntegerを使うのは、Integerが持つメソッドを使いたい時と、値がない場合すなわちnullを表現したい時です。例えば、SQLでは値の有り無しをNULLかどうかで表現できますが、それをJavaintでは上手に表現できません。

ですから、プログラム上では0-1999などの値に特別な意味を持たせたり、Integer.MAX_VALUEMIN_VALUEを使うのですが、確実さには欠けます。そういう値のチェックを忘れるなどのミスもしがちです。

そういう時に参照型であるIntegerを使えば、値がないことをnullとして表現できるのです。Integerをどういう時に使うか分からない方は、その変数でnullを表現する必要があるかを一つの指針にしてみてください。

3-3.オートボクシングでintIntegerを自動変換する

Java 1.5でオートボクシング(auto boxing)という仕組みが導入されました。オートボクシングで、intIntegerをプログラム上でほぼ同じものとして扱えます。

プログラム上でintを使う所ではIntegerを使えますし、Integerを使う所ではintが使えます。本当のプログラム上は相変わらずintIntegerは別物なのですが、その違いをJavaが裏で自動的に変換をしてくれるのです。

Integer intObj = Integer.valueOf("12345"); // Integer
int intPri = 65535; // int

intPri = intObj; // → 12345、intにIntegerを代入できる
intPri = new Integer("65535"); // → 65535、同上
intObj = 12345; // → 12345、Integerにintを代入できる

これでJavaの面倒な部分がある程度解消されました。ですが、前述のとおりIntegernullを表せますが、intは必ず何かの整数なので、nullに相当するものがありません。

ですので、以下のように予期せぬところでNullPointerExceptionが発生したりします。これは2019年のJava 11の時点でも変わっていません。プログラマが注意するか、Optionalを使う必要があります。

class IntTest {
	static Integer returnInteger() {
		return null;
	}

	public static void main(String[] args) {
		int i = returnInteger(); // → nullをintに変換できないので、実行するとNullPointerExceptionが発生する!!
	}
}

3-4.【応用】符号なしintとしての扱い方

この記事ではずっと、intはプラスマイナスがある32ビットの整数だとお伝えしてきました。それは今も変わりませんが、Java 8intを符号なし整数として扱えるメソッドがIntegerに追加されました。それらのメソッドを使うと、int32ビットをフルに使った計算ができます。

例えば以下のようにです。比較しているのは同じintでビットパターンも変わりませんが、compareUnsignedでは32ビット目も含めた整数として比較しているのが分かるでしょうか。

int i1 = Integer.MAX_VALUE; // → 0b01111111111111111111111111111111
int i2 = Integer.MIN_VALUE; // → 0b10000000000000000000000000000000

int cmp1 = Integer.compare(i1, i2);
int cmp2 = Integer.compareUnsigned(i1, i2);

System.out.println(cmp1); // → 1(i1の方が大きい)、i1はプラスなのでi2よりも大きい
System.out.println(cmp2); // → -1(i2の方が大きい)、32ビットをフルに使っているため、i2の方が大きいと判断される

Integer.~Unsigned系のメソッドは以下のものです。それぞれの詳細は、Javadocを参照してみてください。

Integer.toUnsignedString:符号なし整数として文字列化する

Integer.parseUnsignedInt:符号なし整数としてパースする

Integer.toUnsignedLong:符号なし整数としてlongに変換する

Integer.divideUnsigned:符号なし整数として割り算する

Integer.remainderUnsigned:符号なし整数として余りを求める


4.まとめ

この記事では、Javaintについてお伝えしてきました。Javaint32ビットの整数で、±21億くらいまでの値を表現できます。intJavaで整数を使う時の標準ともいえるデータ型です。

Javaでは、整数を表現するにはプリミティブ型のintと、クラス(参照型)としてのIntegerの二種類があり、それらは違うものであることには注意しましょう。ただ、オートボクシングにより違いが見えにくくはなっています。

さて、整数はどんなプログラミング言語にもあるデータ型です。ですので、Javaで整数の使い方を学んでおけば、他のプログラミング言語でもそう大きな違いなく使えるでしょう。

特にビットパターンと数値の対応を覚えておけば、いざという時に役に立つかもしれません。それに、ビットパターンがイメージできれば、コンピュータの世界により深く入り込めるようになります。これを機に、頑張ってみませんか?

私たちは、全てのエンジニアに市場価値を高め自身の望む理想のキャリアを歩んでいただきたいと考えています。もし、今あなたが転職を検討しているのであればこちらの記事をご一読ください。理想のキャリアを実現するためのヒントが見つかるはずです。

『技術力』と『人間力』を高め市場価値の高いエンジニアを目指しませんか?

私たちは「技術力」だけでなく「人間力」の向上をもって遙かに高い水準の成果を出し、関わる全ての人々に感動を与え続ける集団でありたいと考えています。

高い水準で仕事を進めていただくためにも、弊社では次のような環境を用意しています。

  • 定年までIT業界で働くためのスキル(技術力、人間力)が身につく支援
  • 「給与が上がらない」を解消する6ヶ月に1度の明確な人事評価制度
  • 平均残業時間17時間!毎週の稼動確認を徹底しているから実現できる働きやすい環境

現在、株式会社ボールドでは「キャリア採用」のエントリーを受付中です。

まずは以下のボタンより弊社の紹介をご覧いただき、あなたの望むキャリアビジョンをエントリーフォームより詳しくお聞かせください。

コメント

公式アカウントLINE限定!ボールドの内定確率が分かる無料診断実施中
公式アカウントLINE限定!
ボールドの内定確率が分かる無料診断実施中