javaの技術書のほとんどには、javaのソースは中間マシン(JVM)で動作し、JVMが実行環境毎の差分の吸収とメモリ管理を引き受けることが書いてあると思います。
メモリ管理を自動で行う点は、javaを作る際に参考にしているC++との大きな差で利点であると同時に、その動きはプログラマにが意識しずらいという問題を抱えています。
そして、javaのメモリに関する話は中間コードやJVMのレベルの解説書以外で書かれれている場合は基本的にはたとえ話です。
実際の動きを確かめるコードを書きました。実行してみてください。
java
1public class ClassA{
2 public static int a = ClassA.makeA();
3 public static int b = ClassA.makeB();
4 public static int makeA(){
5 System.out.println("makeA");
6 return 1;
7 }
8
9 public static int makeB(){
10 System.out.println("makeB");
11 return 1;
12 }
13
14 // クラス変数は不要のメソッド
15 public static int getC(){
16 System.out.println("makeC");
17 return 1;
18 }
19
20 // 空のコンストラクタ
21 public ClassA(){}
22 public int d = makeD();
23 public int e = makeE();
24
25 public int makeD(){
26 System.out.println("makeD");
27 return 1;
28 }
29
30 public int makeE(){
31 System.out.println("makeE");
32 return 1;
33 }
34 }
クラス変数a,b及びインスタンス変数d,eのメモリが確保されたタイミングでログを書き出すようにクラスの定義をしています。
そして、クラスメソッドgetCは、クラス変数もインスタンス変数も不要です。
この状態でgetCを呼び出してみました。
java
1public class Main {
2 public static void main(String[] args) throws Exception {
3 System.out.println("test");
4 System.out.println("ClassA.getC:" + ClassA.getC());
5 }
6}
7
私がテストした環境では、出力はこのようになりました。
test
makeA
makeB
makeC
ClassA.getC:1
クラス変数の領域を確保してから、クラスメソッドを実行しています。
ポイントとしては、クラス変数a,b両方とも確保している点です。絶対とは言い切れませんが、一度にすべての変数の領域を確保していることがわかると思います。
また、"test"が先に表示されていますので、ClassAのクラスメソッドが初めて実行されるタイミングで領域の確保が行われるという点がわかります。
次に、インスタンスを作ったときのテストをします。
java
1public class Main {
2 public static void main(String[] args) throws Exception {
3 System.out.println("test");
4 ClassA a = new ClassA();
5 }
6}
私の環境ではこのようになりました。
test
makeA
makeB
makeD
makeE
インスタンスを作ったタイミングで、クラス変数の領域も(必要ないのに)確保されました。
このように、実際にテストするとなんとなくイメージがつかめるのではないでしょうか?いろいろためしてみてください。
ところで、バージョンによって全然違う動きをする可能性もあり、ここらへんは現段階ではあまり突っ込まなくても問題がないとは思いませんか?(本の方でお茶を濁しているのも一理あるとおもいます。)
ソースはこちらです。
https://paiza.io/projects/8W5ex0OgDSri8c4mte4JQA
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/05/04 03:22
2017/05/04 12:36