1. 程式人生 > >內部類為什麼不可以定義靜態成員,對靜態的真正理解

內部類為什麼不可以定義靜態成員,對靜態的真正理解

從語法層面來講

比如外部類是Book,他定義了一個成員變數i

當然只能例項化Book,Book book = new Book();

book.i

只能通過這種形式來訪問

但是把i弄成靜態的

就可以直接Book.i

內部類也一樣 上面的

肯定不能直接訪問Book.Book1那又怎麼能訪問Book.Book1.i呢?他定義了這個i為靜態,那肯定應該是支援直接通過類名來訪問的,但是這裡非靜態的class卻是不可直接通過類名訪問的。所以為了支援通過類名來訪問的,他必須讓編譯器禁止這種情況的出現。

從jvm的角度分析

假如你是Book1的情況。先是類載入器查詢到位元組碼(.class檔案),並根據位元組碼建立一個Class物件

連結,驗證類中的位元組碼,為靜態域分配儲存空間。但是分配靜態i的時候,會發現內部類甚至都沒進行Class物件的建立。

請原諒我上面不經過大腦的結論

其實就是考察靜態的概念,也用不著涉及jvm層。

與其問內部類為什麼不能定義靜態成員

不如問靜態方法內部為什麼不可以包含靜態的引用?

所以這個問題就抽象出來了:為什麼靜態成員不允許包含非靜態成員?為什麼靜態成員不可以被非靜態成員容納?

所以引出靜態的定義:靜態成員,不僅他自己需要是靜態的,他的父“容器”也必須是靜態的,他容納的東西也必須是靜態的。這才是靜態的完整定義。

為什麼呢?

為什麼靜態成員不允許包含非靜態成員?

靜態成員不依賴類而存在。假設他內部容納了非靜態的成員,可是在這個類還未載入的時候,只有這個靜態成員是成立的,但是他的非靜態子成員是未成立的狀態,這就不合邏輯,你要去呼叫這個靜態的方法,肯定會出錯。

為什麼靜態成員不可以被非靜態成員容納?這得從記憶體的角度去解釋。

回到我們之前的那個問題。

class NeiBuLei {
    static Book book = new Book();
}
這是一個內部類。這個內部類理論上是要存放在堆(heap)區中。而內部類裡的物件,也要跟隨著外部類的物件存放在heap裡。這裡是把這個new Book()存放在heap中,這個靜態的引用book存放在靜態區中。但是當內部類還沒有被載入的時候,new出一個Book例項的操作根本無法得到執行,不僅如此,整個內部類所在的heap空間都還沒有的申請,那我這裡這個靜態的book引用又該指向誰?外部類就不一樣了,外部類甚至可以認為是靜態的存在。

整個的意思就是:NeiBuLei的例項的空間都沒有申請,指向的又是誰?

------------------

當看了JVM後,又有了深入一步的瞭解。

當你要獲取static的引用時,即對應getstatic位元組碼指令,這個時候,會要求這個內部類必須初始化,然後內部類的初始化必須是以外部類的初始化為前提的(非靜態內部類作為外部類的成員存在)。所以當你獲取static引用的時候,就會發生,內部類初始化了,但是外部類還沒有初始化這樣一個錯誤。這才是正解。