最近在看單例模式的實現,看到有一種利用JAVA靜態內部類的特性來實現,對於內部類我還真是不瞭解,遂瞭解了一下,程式碼貼上。
/** * 內部類分為:成員內部類、區域性內部類、匿名內部類和靜態內部類。 */ public class Demo { /* * 1.成員內部類:成員內部類是最普通的內部類, * 它的定義為位於另一個類的內部。 */ class Inside1 { public void say() { System.out.println("Inside1 say..."); } } /* * 2.區域性內部類:區域性內部類是定義在一個方法或者一個作用域裡面的類, * 它和成員內部類的區別在於區域性內部類的訪問僅限於方法內或者該作用域內。 * 區域性內部類就像區域性變數一樣,是不能有public、protected、private以及static修飾符的。 */ public Demo fun1() { class Woman extends Demo{ int age = 0; } return new Woman(); } /* * 3.匿名內部類:匿名內部類在編譯的時候由系統自動起名為Outter$1.class。 * 一般來說,匿名內部類用於繼承其他類或是實現介面,並不需要增加額外的方法,只是對繼承方法的實現或是重寫 */ public void fun2(){ new JFrame().addKeyListener(new KeyListener() { public void keyTyped(KeyEvent e) {} public void keyReleased(KeyEvent e) {} public void keyPressed(KeyEvent e) {} }); } /* * 4.靜態內部類也是定義在另一個類裡面的類,只不過在類的前面多了一個關鍵字static。 * 靜態內部類是<b>不需要依賴於外部類</b>的,這點和類的靜態成員屬性有點類似, * 並且它不能使用外部類的非static成員變數或者方法,這點很好理解, * 因為在沒有外部類的物件的情況下,可以建立靜態內部類的物件, * 如果允許訪問外部類的非static成員就會產生矛盾,因為外部類的非static成員必須依附於具體的物件。 */ static class Inside3{ } }
上面是內部類的宣告,下面再Main類中去呼叫,看看有什麼值得注意的:
public class Main { public static void main(String[] args) { Demo demo = new Demo(); // 得到一個類的成員內部類,必須先獲取外部類的物件例項 Inside1 inside1 = demo.new Inside1(); } }
註釋也寫清楚了,成員內部類就好像成員變數一樣,首先得到類的資訊必須先獲取外部類的物件例項,然後再通過new來建立內部類的例項。
注意這個地方有個注意的地方,正如我們所知道的,成員變數會在類物件建立的時候都會進行初始化,那麼成員內部類在外部類物件建立的時候有沒有被載入?--這裡引出另一個問題,如何檢視一個是否載入?一種方法是在類中寫static程式碼塊,但是類載入的時候也可以不執行static程式碼塊的,請看Class.forName()的過載方法,這裡利用JDK提供的jVisualvm工具,能以視覺化的方法,看到JVM內的情況,看測試程式碼:
public class Demo { class Inside1 { public void say() { System.out.println("Inside1 say..."); } } }
先將Demo類寫一個成員內部類,然後再Main類中建立外部類的物件,用JVisualVM檢視Inside1類是否被載入。
public class Main { public static void main(String[] args) { Demo demo = new Demo(); //為了能讓此程式停住方便除錯 new Scanner(System.in).nextLine(); } }
檢視類是否Demo$Inside1類是否被載入:
可以看到,Demo開頭的類,之家在了Demo類自己,也就是說當外部類生成例項物件的時候,外部類中內部類並不參與初始化。那麼靜態內部類呢?
下面將Demo中Inside內部類程式設計static靜態的,然後再載入外部類或者建立外部類的例項,Main方法不變,看看什麼情況:
public class Demo { static class Inside1 { public void say() { System.out.println("Inside1 say..."); } } }
踏噠~
還是隻有一個外部類Demo,所以說不管內部類是靜態的還是非靜態的,都不會因為外部類的類載入或者物件建立而去載入、初始化,一般是這樣的,也有可能不是:
public class Demo { public Demo say() { class Inside1 extends Demo{ } return new Inside1(); } }
main方法還是不變,請看JVM類載入情況:
Inside1被載入了,至於為啥,我還不知道,希望有知道的可以指點一下。