靜態內部類不持有外部類的引用
這個觀點是眾所周知的。雖然明白是因為其構造函數內沒有傳入外部類的引用。可是為什麼靜態類可以沒有傳入引用呢,靜態內部類的加載又是什麼樣的過程呢?
這幾天找到的答案,似乎都不能讓我有一種豁然開朗的感覺。於是一次新探索開始了~
一開始,我是這樣想的:
靜態類和靜態對象,靜態變量,靜態塊等等一樣,是在類初始化時就被加載的,所以可以不需要傳入當前類的引用。 (關於非靜態內部類,就不需要多說,一定需要外部類先實例化後才會加載。)
通過網上一個代碼的思路,我寫出了以下demo:
<code>import java.util.Random;public
class
OuterClass
{public
static
long
OUTER_DATE = System.currentTimeMillis();static
{ System.out
.println("外部類靜態塊加載時間:"
+ System.currentTimeMillis()); }public
OuterClass
() { timeElapsed(); System.out
.println("外部類構造函數時間:"
+ System.currentTimeMillis()); }static
class
InnerStaticClass
{public
static
long
INNER_STATIC_DATE = System.currentTimeMillis(); }class
InnerClass
{public
long
INNER_DATE =0
;public
InnerClass
() { timeElapsed(); INNER_DATE = System.currentTimeMillis(); } }
public
static
void
main
(String[] args
) { OuterClass outer =new
OuterClass(); System.out
.println("外部類靜態變量加載時間:"
+ outer.OUTER_DATE); System.out
.println("非靜態內部類加載時間"
+outer.new
InnerClass().INNER_DATE); System.out
.println("靜態內部類加載時間:"
+InnerStaticClass.INNER_STATIC_DATE); }private
void
timeElapsed
() {for
(int
i =0
; i10000000
; i++) {int
a =new
Random(100
).nextInt(), b =new
Random(100
).nextInt(); a = a + b; } } }/<code>
假如我的推想沒有錯誤的話,我想應該會這樣的:
外部類常量加載時間 = 外部類靜態塊加載時間 = 靜態內部類加載時間 < 外部類構造函數時間< 非靜態內部類加載時間
Ok,我以為我離走到人生顛覆只差一個Run了 ! ✧(๑•̀ㅂ•́)و✧
結果卻是:
不過,從上面我們可以分析出來結果是:
靜態內部類和非靜態內部類一樣,都是在被調用時才會被加載
不信的同學可以自己試試copy以上的代碼。隨機調換main()函數里的方法調用順序,來驗證以上的規律。
後來我這麼想:
靜態內部類其實和外部類的靜態變量,靜態方法一樣,只要被調用了都會讓外部類的被加載。不過當只調用外部類的靜態變量,靜態方法時,是不會讓靜態內部類的被加載
嗯哼~還是來一個demo,不過是改動了點上面的東西:
<code>import java.util.Random;public
class
OuterClass
{public
static
long
OUTER_DATE = System.currentTimeMillis();public
static
int
a =1
;static
{ System.out
.println("外部類靜態塊加載時間:"
+ System.currentTimeMillis()); }public
OuterClass
() { timeElapsed(); System.out
.println("外部類構造函數事件:"
+ System.currentTimeMillis()); }static
class
InnerStaticClass
{static
{ System.out
.println("內部類靜態塊加載時間:"
+ System.currentTimeMillis()); }public
static
double
INNER_DATE = System.currentTimeMillis(); }class
InnerClass
{public
long
INNER_DATE =0
;public
InnerClass
() { timeElapsed(); INNER_DATE = System.currentTimeMillis(); } }public
static
void
Hello
(){System.out
.println("Hello"
);}public
static
void
main
(String[] args
) { OuterClass.Hello(); OuterClass outer =new
OuterClass(); System.out
.println("外部類靜態變量加載時間:"
+ OuterClass.OUTER_DATE); System.out
.println("外部類靜態變量加載時間:"
+ outer.OUTER_DATE); }private
void
timeElapsed
() {for
(int
i =0
; i10000000
; i++) {int
a =new
Random(100
).nextInt(), b =new
Random(100
).nextInt(); a = a + b; } } }/<code>
結果如下:
觀點1:我說的沒錯吧~,調用外部類的靜態變量,靜態方法可以讓外部類得到加載,不過這裡靜態內部類沒有被加載
再看看下面的這段:
<code>import java.util.Random;public
class
OuterClass
{public
static
long
OUTER_DATE = System.currentTimeMillis();public
static
int
a =1
;static
{ System.out
.println("外部類靜態塊加載時間:"
+ System.currentTimeMillis()); }public
OuterClass
() { timeElapsed(); System.
out
.println("外部類構造函數事件:"
+ System.currentTimeMillis()); }static
class
InnerStaticClass
{static
{ System.out
.println("內部類靜態塊加載時間:"
+ System.currentTimeMillis()); }public
static
long
INNER_STATIC_DATE = System.currentTimeMillis(); }class
InnerClass
{public
long
INNER_DATE =0
;public
InnerClass
() { timeElapsed(); INNER_DATE = System.currentTimeMillis(); } }public
static
void
Hello
(){System.out
.println("Hello"
);}public
static
void
main
(String[] args
) { System.out
.println("內部類靜態變量加載時間:"
+ InnerStaticClass.INNER_STATIC_DATE ); System.out
.println("外部類靜態變量加載時間:"
+ OuterClass.OUTER_DATE ); }private
void
timeElapsed
() {for
(int
i =0
; i10000000
; i++) {int
a =new
Random(100
).nextInt(), b =new
Random(100
).nextInt(); a = a + b; } } }/<code>
結果:
觀點2:可以看出,我們其實加載靜態內部類的時候,其實還會先加載外部類,才加載靜態內部類
由觀點1與觀點2聯立,以上論點得證!
好,迴歸主題,為什麼靜態內部類可以不傳入引用呢?
因為其本質就是針對外部類的內部類,而不是對象的內部類,不必用this來調用。
首先,從靜態的概念出發理解,靜態修飾過後的一切物件都只與類相關,不與對象引用相關
As we known,靜態變量,靜態方法,靜態塊等都是類級別的屬性,而不是單純的對象屬性。他們在類第一次被使用時被加載(記住,是一次使用,不一定是實例化)。我們可以簡單得用 類名.變量 或者 類名.方法來調用它們。與調用沒有被static 修飾過變量和方法不同的是:一般變量和方法是用當前對象的引用(即this)來調用的,靜態的方法和變量則不需要。從一個角度上來說,它們是共享給所有對象的,不是一個角度私有 。這點上,靜態內部類也是一樣的。
靜態內部類的加載過程:
靜態內部類的加載不需要依附外部類,在使用時才加載。不過在加載靜態內部類的過程中也會加載外部類。以上花了很多功夫來說明了