Java變數可分為局部變數和成員變數,其中局部變數又可分為三類:形參、方法內局部變數、代碼塊局部變數。
類體內定義的變數稱為成員變數(Field),沒有使用static修飾的稱為非靜態變數或執行個體變數;如果使用static修飾就稱為靜態變數或類變數。
對於執行個體變數而言,該類每建立一次執行個體,就需要為執行個體變數分配一塊記憶體空間。
執行個體變數初始化記憶體配置:
我們來看下面這段代碼
public class Test {String name;int age;public Test(String name ,int age){System.out.println("構造器");this.name = name; //weight = 2.5;this.age = age;}{System.out.println("非靜態構造器");weight = 2.0;}public String toString(){System.out.println(weight);return "";}double weight = 2.3;public static void main(String[] args) {Test ti = new Test("x", 4);ti.toString();}}
問題:這裡輸出結果是什嗎?weight是什嗎?
答:輸出結果為:
"非靜態構造器"
"構造器"
2.3
是不是有人覺得輸出2.3很奇怪?
該代碼執行順序是這樣的:
1.在棧記憶體中申請weight的空間,注意此時是預設值即0.0
2.執行非靜態構造器,注意只分配空間不會賦值,因此對於這段代碼來說沒有任何意義。
3.執行建構函式賦值,賦值順序按照指定初始值和非靜態構造器順序賦值,也就說在執行new Test()的時候才對weight賦值
先賦給2.0,再賦給2.3,最後執行構造器中的剩餘的方法。(最終值為2.5而不是2.3)
因此也就是說:執行個體變數的初始化過程都是先在堆記憶體中申請空間,無論何時賦值,最先都是在調用構造器的時候才會對其賦值,賦值的順序按照初始化值或非靜態初始化塊的順序執行,最後執行建構函式中的賦值。
類變數初始化記憶體配置:
類變數初始化過程與實力變數類似,只不過由:申請空間-建構函式-賦值三步簡化為:申請空間-賦值兩部了。我們來看下面例子:
Class Price{ final static Price INSTANCE = new Price(2.8); static double initPrice = 20; double currentPrice; public Price(double discount){ currentPrice = initPrice - discount; }}main(){ system.out.println(Price.INSTANCE.currentPrice);}
問題:這裡輸出結果是什嗎?
答:輸出結果為:
-2.8
是不是有人覺得輸出-2.8很奇怪?
該代碼執行順序是這樣的:
1.在棧記憶體中申請INSTANCE和initPrice的空間;
2.按照順序賦值,先執行new Price();,此時initPrice的值為預設值即0。因此currentPrice = -2.8
3.initPrice賦值20