広告 Java

Javaのプリミティブ型と参照型の違いを分かりやすく解説

はじめに

Javaのデータ型には、プリミティブ型と参照型があります。

プリミティブ型と参照型の違いを説明できるかな?
え・・・わからないです。

次の例では、プリミティブ型と参照型の違いをあらわしています。

[プリミティブ型と参照型の例]

package demo;

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チャー または キャラ文字
Javaでは変数を定義するときに使う基本的なデータ型のことをプリミティブ型といいます。

プリミティブ型のデータの持ち方

データはメモリ上で管理されており、プリミティブ型のデータは、メモリ上に直接値が格納されています。

プリミティブ型のデータの持ち方

このプリミティブ型のデータを「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には、プリミティブ型に対応したクラスが用意されています。これらのクラスのことをラッパークラスといいます。

ラッパークラスには、プリミティブ型に対する便利なメソッドが用意されています。またラッパークラスはクラスなのでnullを代入することができます。
基本データ型ラッパークラス
byteByte
shortShort
intInteger
longLong
floatFloat
doubleDouble
charCharacter
booleanBoolean

 

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のイメージ例です。

immutableのイメージ例

はじめに「String a = "あ"」と定義しStringのオブジェクトを生成、このオブジェクトは「100番地の実体のアドレス」を参照しています。そして「a = "い"」と値を変更すると、新しい領域を確保し「102番地の実体のアドレス」を参照します。

 

それでは、さきほどのラッパークラスの例で考えてみます。

immutableラッパークラスの例

ラッパークラスは参照型だがimmutableの変数のため、上記のように参照型のオブジェクトを「Integer b = a」のように別の参照型に代入し「b = 1」のように値を変更すると、メモリ上では別領域に新たな参照を作ります。

そのため、Stringやラッパークラスは参照型だがプリミティブ型のような動きになっています。

なるほど、同じ参照型でもStringとラッパークラスは扱いが違うんですね。

helpful