技術とか戦略とか

IT技術者が技術や戦略について書くブログです。

java:プリミティブ型とオブジェクト型のメモリの持ち方の違い

を酒の席で聞かれてうまく答えられなかったので、改めて勉強し直してみました。
 
1.そもそもプリミティブ型(基本データ型)って何だっけ
値型のことで、オブジェクトを持たない型のことです。
javaの場合は以下の8つの型が該当します。
 
Primitive Data Types (The JavaTM Tutorials Learning the Java Language Language Basics)

https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html

 
・byte
・short
・int
・long
・float
・double
・boolean
・char
 
2.プリミティブ型とオブジェクト型(参照型、クラス型)のメモリの持ち方の違い
いよいよ本題。
以下のページでうまくまとめられていました。
 
図で理解するJavaの参照

https://qiita.com/hys-rabbit/items/2e94c8722dc8f950e77c
 
C言語の経験があったので、オブジェクト型がC言語で言うポインタと同じような動きをすることは直感的に理解していました。
例えば、String型の比較を行う時に、「==」で比較すると2つの変数が同じメモリの位置を指していないと真にならず、値が一致することを確認したい場合はequalsメソッドを使う必要があったので、そこでなんとなくそう思っていました。
java開発者の言葉にまだ慣れていないだけかな…と思って流そうとしたのですが、記事を読み進めたらどうやらそもそもの理解が不足していたことがわかりました。
 
以下は上記記事からの引用です。
 
---引用開始---
//【B】参照型
char arrayA = {'A', 'B', 'C'};
char
arrayB = arrayA;
arrayB[0] = 'D';
System.out.println(arrayA[0]); // D
System.out.println(arrayB[0]); // D

//【C】参照型(イミュータブル)
String stringA = "文字列";
String stringB = stringA;
stringB = "もじれつ";
System.out.println(stringA); // 文字列
System.out.println(stringB); // もじれつ
---引用終了---
 
意味がわからん。イミュータブルって何だ?【C】のstringAは「もじれつ」になるんじゃないのか?
 
というわけで、イミュータブルについても調べました。
 
3.イミュータブルについて
2で引用した記事にもイミュータブルについて解説されていましたが、もう少し詳しく書かれているページも見てみました。
 
Javaでimmutableを試す - abcdefg.....

http://pppurple.hatenablog.com/entry/2017/03/20/203053
 
早い話、以下の特徴を持つ型がイミュータブルな型となるようです。
・「すべてのフィールドをfinalかつprivateにする」等の条件を満たす
・標準で用意されている型だとStringはイミュータブルな型
 
イミュータブルな型の変数については、下記図のような挙動になると理解しました。

f:id:akira2kun:20180923125402j:plain

 
関数の引数についてイミュータブルか否かでどのような挙動の違いが出るのかも気になったので、これも確認しました。
 
【Java初心者】値渡しと参照渡し

https://qiita.com/chihiro/items/d3d9a028cd5dd8e84649
 
イミュータブルな型ではない場合の例
---引用開始---
// class宣言等は省略
int num = {10,20};
methodB(num);
System.out.println(num[0]); // 20が出力されます

void methodB(int num){
num[0] += 10;
System.out.println(num[0]); // 20が出力されます
}
---引用終了---
 
イミュータブルな型の場合の例
---引用開始--- ※コメントは加工
// class宣言等は省略
String text = "A";
methodC(text);
System.out.println(text); // A

void methodC(String text){
text = "B";
System.out.println(text); // B
}
---引用終了---
 
イミュータブルな型ではない場合は典型的な参照渡しの挙動になりますが、イミュータブルな型の場合は
・呼び出し元の変数textの値ががメソッド内のローカル変数textにコピーされる
・ローカル変数textの値を変更する
 =新たに領域を確保し、ローカル変数textはその領域を参照するように変更する
・参照先が変わったのはローカル変数textのみ、呼び出し元の変数textは変更されない
という挙動になるようです。
 
軽い気持ちで調べたのですが、思ったよりも濃い内容でした。
まだまだ勉強が足りませんね…。