1. 程式人生 > >很考驗人的java內存加載面試題

很考驗人的java內存加載面試題

ons .com 代碼段 一樣在 found 代碼 過程 方式 cto

源代碼如下,求結果

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內存加載面試題