咱們先來區分一下兩個概念:類加載、加載。java
類加載的過程包括加載,初始化,驗證,解析,準備,初始化等五個過程。加載是類加載的一部分。面試
區分完這兩個概念以後咱們再來看下面的問題。app
咱們聲明一個類,這個類有個內部靜態類。還有主函數,當咱們啓動程序以後,運行java application程序。函數
運行結果是什麼呢?.net
下面看個代碼實現的例子:對象
package Test;
public class OuterClass {
static {
System.out.println("加載外部類");
}
static class InnerClass{
public InnerClass() {}
static {
System.out.println("加載內部類");
}
static void innerMethod() {
System.out.println("內部類的靜態方法");
}
static int a;
}
public static void main(String[] args) {
OuterClass out=new OuterClass();
System.out.println("=============");
// OuterClass.InnerClass.a=1;
}
}
blog
外部類的靜態代碼塊執行了。內部類的靜態代碼塊沒有執行在外部類執行靜態代碼塊以後執行,是由於內部類沒有加載麼?內存
其實不是這樣的,一旦程序運行,全部該類涉及的類(包括內部類和從其餘包導入的類)都會在類加載的過程當中加載到get
內存,由於在整個程序運行的過程當中類加載只會發生一次,一旦某個類沒有被加載,那麼將不能再使用這個類。博客
注意我標出來的加載,這裏是指在類加載過程當中的加載,可是咱們能夠在網上了解或者在書上得知,只有當某個類
初始化以後,纔會調用類的靜態代碼塊。纔會執行對應的。那麼何時執行類加載過程當中的類初始化呢?
只有當咱們有對類的引用的時候,纔會將類初始化。
好比咱們new一個非靜態類的對象,或者對某個靜態類的成員(包括成員方法和域)或者調用有訪問的時候
若是咱們把最後一行的註釋去掉,就會執行內部靜態類的靜態代碼塊(static{})。
或者有隱式的調用咱們類的方法。爲何咱們的外部類沒有new的時候還會執行他的靜態代碼塊呢?
是否是忘了還有個主函數在執行,這時候是調用了類的方法的,因此會初始化這個外部類。執行外部類的靜態代碼塊。
關於靜態代碼塊,代碼塊,類的構造函數執行順序問題不態理解的同窗能夠看看個人博客:
Java面試題 類的構造函數的執行順序問題
注意:內部靜態類不會自動初始化,只有調用靜態內部類的方法,靜態域,或者構造方法的時候纔會加載靜態內部類。
利用這種特色咱們能夠實現一個單例模式
package Test;
public class Single {
private Single() {}
static class SingleHolder {
private static final Single instance=new Single();
}
public static Single getinstance() {
return SingleHolder.instance;
}
public static void main(String[] args) {
Single a=Single.getinstance();
Single b=Single.getinstance();
Single c=Single.getinstance();
System.out.println(a.toString());
System.out.println(b.toString());
System.out.println(c.toString());
}
}
上面程序的運行結果:
當咱們用的構造方法聲明爲private的時候,表明這個類只能被本身調用,就算同包下的類也不能實例化。
這並非構造函數只會被調用一次,而且保證只會實例化一次類的緣由。若是你把上面的構造函數變成public,
也是隻生成一個對象。