はじめに
Javaのデータ型には、プリミティブ型と参照型があります。
次の例は、プリミティブ型と参照型の違いをあらわしています。
[プリミティブ型と参照型の例]
public class Sample {
public static void main(String[] args) {
// プリミティブ型
int a = 0;
int b = a;
b = 1;
System.out.println("プリミティブ型 変数 a =" + a);
System.out.println("プリミティブ型 変数 b =" + b);
// 参照型
int[] c = new int[1];
c[0] = 0;
int[] d = c;
d[0] = 1;
System.out.println("参照型 配列 c =" + c[0]);
System.out.println("参照型 配列 d =" + d[0]);
}
}
[実行結果]
プリミティブ型 変数 a =0
プリミティブ型 変数 b =1
参照型 配列 c =1
参照型 配列 d =1
プリミティブ型
プリミティブ型とは基本的なデータ型のことです。
スポンサーリンク
Javaのプリミティブ型には次のようなものがあります。
データ型 | 読み方 | 格納できる値 |
byte | バイト | -128 ~ 127の整数 |
short | ショート | -32768 ~ 32767の整数 |
int | イント | -2147483648 ~ 2147483647の整数 |
long | ロング | -9223372036854775808 ~ 9223372036854775807の整数 |
float | フロート | ±3.40282347E+38 ~ ±1.40239846E-45の小数点を含む数値 |
double | ダブル | ±1.79769313486231570E+308 ~ ±4.94065645841246544E-324の小数点を含む数値 |
boolean | ブーリアン | true または false |
char | チャー または キャラ | 文字 |
プリミティブ型のデータの持ち方
データはメモリ上で管理されており、プリミティブ型のデータは、メモリ上に直接値が格納されています。
このプリミティブ型のデータを「int b = a」のように別のプリミティブ型に代入すると、次のようにメモリ上の値をコピーします。この結果、お互い別の値(実体)を参照しています。
[プリミティブ型の例]
// プリミティブ型
int a = 0;
int b = a;
b = 1;
System.out.println("プリミティブ型 変数 a =" + a);
System.out.println("プリミティブ型 変数 b =" + b);
[実行結果]
プリミティブ型 変数 a =0
プリミティブ型 変数 b =1
上記で説明したとおり、プリミティブ型のデータを「int b = a」のように別のプリミティブ型に代入すると次のように、メモリ上の値をコピーします。
今回の例も同じで「int a」と「int b」は別の値(実体)を参照しているので、「変数a」の値は「0」、「変数b」の値は「1」となっています。
参照型
参照型とは、配列やクラスのようにnew演算子を用いてオブジェクトを生成してから使用するデータ型のことです。
スポンサーリンク
参照型のデータの持ち方
データはメモリ上で管理されており、参照型はメモリ上のアドレスを参照しています。
以下は参照型のイメージ例です。プリミティブ型はメモリ上の値(実体)を直接参照していましたが、参照型は値(実体)を格納しているメモリ上のアドレスを参照しています。
この参照型のオブジェクトを「int[] d = c」のように別の参照型に代入すると、次のようにメモリ上のアドレスをコピーします。この結果、お互い同じ値(実体)を参照しています。(どちらも実体が格納されている100番地のアドレスを参照している)
[参照型の例]
// 参照型
int[] c = new int[1];
c[0] = 0;
int[] d = c;
d[0] = 1;
System.out.println("参照型 配列 c =" + c[0]);
System.out.println("参照型 配列 d =" + d[0]);
[実行結果]
参照型 配列 c =1
参照型 配列 d =1
上記で説明したとおり、参照型のオブジェクトを「int[] d = c」のように別の参照型に代入すると、次のようにメモリ上のアドレスをコピーします。
今回の例も同じで「int[] c」と「int[] d」は同の値(実体)を参照しているので、どちらかの配列の値を変更すると、もう片方の配列の値も変わります。そのため、「int[] c」と「int[] d」には同じ値が格納されています。
Stringとラッパークラスの扱い
Javaには、プリミティブ型に対応したクラスが用意されています。これらのクラスのことをラッパークラスといいます。
基本データ型 | ラッパークラス |
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
char | Character |
boolean | Boolean |
Stringやラッパークラスはクラスなので参照型です。ただし、扱いが他の参照型とは違うので注意が必要です。
[ラッパークラスの例]
public class Sample2 {
public static void main(String[] args) {
// ラッパークラス
Integer a = 0;
Integer b = a;
b = 1;
System.out.println("ラッパークラス 変数 a =" + a);
System.out.println("ラッパークラス 変数 b =" + b);
}
}
[実行結果]
ラッパークラス 変数 a =0
ラッパークラス 変数 b =1
ラッパークラスは参照型なので、変数aとbは同じ実体を参照しているはずですが、そうなっていません。
Stringやラッパークラスは、immutable(イミュータブル)と呼ばれる変数です。immutableとは、不変という意味で、1度定義したオブジェクトは変えないということです。
Stringやラッパークラスはimmutableの変数なので、1度定義したオブジェクトを変更できません。
そのため、Stringやラッパークラスの値を変更すると、新たな領域が確保されその領域を参照します。(値が同じ場合は、新たな領域は作らず再利用される)
以下はStringのイメージ例です。
はじめに「String a = "あ"」と定義しStringのオブジェクトを生成、このオブジェクトは「100番地の実体のアドレス」を参照しています。そして「a = "い"」と値を変更すると、新しい領域を確保し「102番地の実体のアドレス」を参照します。
それでは、さきほどのラッパークラスの例で考えてみます。
ラッパークラスは参照型だがimmutableの変数のため、上記のように参照型のオブジェクトを「Integer b = a」のように別の参照型に代入し「b = 1」のように値を変更すると、メモリ上では別領域に新たな参照を作ります。
そのため、Stringやラッパークラスは参照型だがプリミティブ型のような動きになっています。