Java 靜態內部類的加載時機

靜態內部類不持有外部類的引用

這個觀點是眾所周知的。雖然明白是因為其構造函數內沒有傳入外部類的引用。可是為什麼靜態類可以沒有傳入引用呢,靜態內部類的加載又是什麼樣的過程呢?

這幾天找到的答案,似乎都不能讓我有一種豁然開朗的感覺。於是一次新探索開始了~


一開始,我是這樣想的:

靜態類和靜態對象,靜態變量,靜態塊等等一樣,是在類初始化時就被加載的,所以可以不需要傳入當前類的引用。 (關於非靜態內部類,就不需要多說,一定需要外部類先實例化後才會加載。)

通過網上一個代碼的思路,我寫出了以下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

; i

10000000

; i++) {

int

a =

new

Random(

100

).nextInt(), b =

new

Random(

100

).nextInt(); a = a + b; } } }/<code>


假如我的推想沒有錯誤的話,我想應該會這樣的:

外部類常量加載時間 = 外部類靜態塊加載時間 = 靜態內部類加載時間 < 外部類構造函數時間< 非靜態內部類加載時間

Ok,我以為我離走到人生顛覆只差一個Run了 ! ✧(๑•̀ㅂ•́)و✧

結果卻是:

Java 靜態內部類的加載時機


不過,從上面我們可以分析出來結果是:

靜態內部類和非靜態內部類一樣,都是在被調用時才會被加載

不信的同學可以自己試試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

; i

10000000

; i++) {

int

a =

new

Random(

100

).nextInt(), b =

new

Random(

100

).nextInt(); a = a + b; } } }/<code>


結果如下:

Java 靜態內部類的加載時機

觀點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

; i

10000000

; i++) {

int

a =

new

Random(

100

).nextInt(), b =

new

Random(

100

).nextInt(); a = a + b; } } }/<code>


結果:

Java 靜態內部類的加載時機

觀點2:可以看出,我們其實加載靜態內部類的時候,其實還會先加載外部類,才加載靜態內部類

由觀點1與觀點2聯立,以上論點得證!

好,迴歸主題,為什麼靜態內部類可以不傳入引用呢?

因為其本質就是針對外部類的內部類,而不是對象的內部類,不必用this來調用

首先,從靜態的概念出發理解,靜態修飾過後的一切物件都只與類相關,不與對象引用相關

As we known,靜態變量,靜態方法,靜態塊等都是類級別的屬性,而不是單純的對象屬性。他們在類第一次被使用時被加載(記住,是一次使用,不一定是實例化)。我們可以簡單得用 類名.變量 或者 類名.方法來調用它們。與調用沒有被static 修飾過變量和方法不同的是:一般變量和方法是用當前對象的引用(即this)來調用的,靜態的方法和變量則不需要。從一個角度上來說,它們是共享給所有對象的,不是一個角度私有

。這點上,靜態內部類也是一樣的。


靜態內部類的加載過程:

靜態內部類的加載不需要依附外部類,在使用時才加載。不過在加載靜態內部類的過程中也會加載外部類。以上花了很多功夫來說明了




分享到:


相關文章: