很考驗人的java內存加載面試題
源代碼如下,求結果
public class MemoryAnalyse { public static int k = 0; public static MemoryAnalyse t1 = new MemoryAnalyse("t1"); public static MemoryAnalyse t2 = new MemoryAnalyse("t2"); public static int i = print("i"); public static int j = print("j"); public static int n = 99; { print("constructor code"); } static { print("static code"); } public static int print(String s) { System.out.println("i=" + i + " " + s + " k=" + k + " n=" + n + " j=" + j); ++i; ++k; ++n; return i; }public MemoryAnalyse(String string) { print(string); } public static void main(String[] args) throws ClassNotFoundException { MemoryAnalyse d = new MemoryAnalyse("T"); } }
然而結果是這個
i=0 constructor code k=0 n=0 j=0 i=1 t1 k=1 n=1 j=0 i=2 constructor code k=2 n=2 j=0 i=3 t2 k=3 n=3 j=0 i=4 i k=4 n=4 j=0 i=5 j k=5 n=5 j=0 i=6 static code k=6 n=99 j=6 i=7 constructor code k=7 n=100 j=6 i=8 T k=8 n=101 j=6
有沒有很驚訝,結果竟然這麽復雜.好,下面我們分析一下,在分析之前,先普及下不怎麽用的基礎知識
代碼塊和靜態代碼塊何時運行問題:
代碼塊在創建對象時運行
靜態代碼塊在類加載時運行
大家都知道static是屬於類的並非對象,也就是說static修飾的東西都會在class加載到方法區時就存在在那裏.所以方法區中類加載時內存過程如下
1.當類剛加載時會全部加載到方法區時,此時所有變量全部未實例化.
2.實例化參數t1
此時因為代碼塊在創建對象時執行,且在構造函數之前執行,所以先執行代碼塊
{ print("constructor code"); }
因為此時所有的變量都為默認值,所以執行後打印結果為
i=0 constructor code k=0 n=0 j=0
此時i,n,k的值都已經自加一,值為1
然後實例化調用構造函數
public MemoryAnalyse(String string) { //這裏string為t1 print(string); }
構造函數調用結果如下
i=1 t1 k=1 n=1 j=0
此時i,n,k的值都已經自加一,值為2
3.實例化參數t2
和第一步一樣在構造函數之前執行代碼塊
{
print("constructor code");
}
i=2 constructor code k=2 n=2 j=0
此時i,n,k的值都已經自加一,值為3
然後實例化調用構造函數
public MemoryAnalyse(String string) { //這裏string為t2
print(string);
}
構造函數調用結果如下
i=3 t2 k=3 n=3 j=0
此時i,n,k的值都已經自加一,值為4
4.初始化參數i
這裏直接調用print("i")函數,得到結果為
i=4 i k=4 n=4 j=0
此時i,k,j值為5,註意i的值不是通過自加一變成5的,而是通過函數的返回值賦給i的
5.初始化參數j
這裏和上一步一樣,執行print("j"),然後把函數的返回值賦給j,打印結果為
i=5 j k=5 n=5 j=0
此時j的值已經為6
到這裏類加載的內部參數變化就完成了,我們可以用加載類的方式調用一下
public static void main(String[] args) throws ClassNotFoundException { //MemoryAnalyse d = new MemoryAnalyse("T"); Class.forName("MemoryAnalyse"); }
Class.forName(類名字符串)是手動加載類到方法區,得到結果為
i=0 constructor code k=0 n=0 j=0
i=1 t1 k=1 n=1 j=0
i=2 constructor code k=2 n=2 j=0
i=3 t2 k=3 n=3 j=0
i=4 i k=4 n=4 j=0
i=5 j k=5 n=5 j=0
i=6 static code k=6 n=99 j=6 //這行的出現是因為static代碼段在類加載時執行.n=99是因為類加載了,n的初值為99把之前的值覆蓋掉了
然後改為我們之前的demo
public static void main(String[] args) throws ClassNotFoundException { MemoryAnalyse d = new MemoryAnalyse("T"); //Class.forName("MemoryAnalyse"); }
執行結果為
i=0 constructor code k=0 n=0 j=0
i=1 t1 k=1 n=1 j=0
i=2 constructor code k=2 n=2 j=0
i=3 t2 k=3 n=3 j=0
i=4 i k=4 n=4 j=0
i=5 j k=5 n=5 j=0
i=6 static code k=6 n=99 j=6
i=7 constructor code k=7 n=100 j=6 //代碼塊執行
i=8 T k=8 n=101 j=6 //構造函數執行
最後兩行的出現就很簡單了,一個是代碼塊的,一個是構造函數的
這麽一分析是不是簡單了很多
很考驗人的java內存加載面試題