獲取Class對象引用的兩種方法

今天從新翻閱Thanking in java。發現經過類字面常量得到Class對象的引用和Class.forName()方式有些區別。特記錄下。 html

 http://bbs.itheima.com/thread-23776-1-1.html?fstgj java

之前的學習網站,-全套java視頻教程,須要的本身看下,能夠去這個網站下載,下載視頻免費,不須要註冊和作什麼任務 數組

1.Class.forName(String className): 安全

    這種方式要注意className必須使用全限定名(即包含完整的包名) dom

2.類字面常量 學習

   好比:FancyToy.class 網站

   這樣作的優勢是:1.編譯器會對其進行檢查,不須要置於try語句塊中。因此更簡單,更安全。 spa

                          2.根除了對forName()方法的調用,故更高效。 .net

   類字面常量不只能夠應用於普通的類,也能夠應用於接口,數組,以及基本數據類型。 視頻

   另外對於基本數據類型的包裝器,有一個標準的TYPE字段,該字段是一個引用,分別指向對應的基本數據類型的Class對象,即boolean.class等價於Boolean.TYPE,void.class等價於Void.TYPE等等。可是要注意Boolean.TYPE和Boolean.class的區別,是不一樣的。

 

3.一個很重要的區別。

爲了使用類,須要通過三個步驟:

  1. 加載: 這是由類的加載器執行的。該步驟將查找字節碼,並從這些字節碼中建立一個Class對象。

  2. 連接: 在連接階段將驗證類中的字節碼,爲靜態域分配存儲空間,而且若是必要的話,將解析這個類建立的對其餘類的全部引用。

  3. 初始化: 若是該類具備超類,則對其初始化,執行靜態初始化器和靜態初始化塊。

forName()這種方式會徹底通過這三步。可是".class"方式,第三步會延遲,延遲到對靜態方法或者很是數靜態域進行首次引用時才執行,請看下面的代碼:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
package bells;
 
import java.util.Random;
 
/**
 * @author bells
 *
 */
public class TestClassInitialization {
 
    public static Random rand =new Random(47);
 
    /**
     * @param args
     */
    public static void main(String[] args)throws Exception {
 
        Class initable = Initable.class;
        System.out.println("After creating Initable ref");
        System.out.println(Initable.staticFinal); //這裏Initable的static塊不會被初始化,由於staticFinal是編譯器常量
        System.out.println(Initable.staticFinal2);
 
        System.out.println(Initable2.staticNonFinal);
 
        Class initable3 = Class.forName("typeinfo.Initable3");
        System.out.println("After creating Initable3 ref");
        System.out.println(Initable3.staticNonFinal);
 
    }
 
}
 
class Initable {
    static final int staticFinal =47;
    static final int staticFinal2 = TestClassInitialization.rand.nextInt(1000);
    static {
        System.out.println("Initializing Initable");
    }
}
 
class Initable2 {
    static int staticNonFinal =147;
    static {
        System.out.println("Initaialzing Initable2");
    }
}
 
class Initable3 {
    static int staticNonFinal =74;
    static {
        System.out.println("Initializing Initable3");
    }
}

  運行結果以下:

從結果中能夠看到,僅僅使用.class語法來得到對類的引用不會引發初始化。可是Class.forName()會當即進行初始化。

還有一點:若是一個static final值是「編譯期常量」,就像Initable.staticFinal那樣,則這個值不須要對Initable類進行初始化就能夠被讀取。記住必定要是編譯期常量才行。今天從新翻閱Thanking in java。發現經過類字面常量得到Class對象的引用和Class.forName()方式有些區別。特記錄下。

 

1.Class.forName(String className):

    這種方式要注意className必須使用全限定名(即包含完整的包名)

2.類字面常量

   好比:FancyToy.class

   這樣作的優勢是:1.編譯器會對其進行檢查,不須要置於try語句塊中。因此更簡單,更安全。

                          2.根除了對forName()方法的調用,故更高效。

   類字面常量不只能夠應用於普通的類,也能夠應用於接口,數組,以及基本數據類型。

   另外對於基本數據類型的包裝器,有一個標準的TYPE字段,該字段是一個引用,分別指向對應的基本數據類型的Class對象,即boolean.class等價於Boolean.TYPE,void.class等價於Void.TYPE等等。可是要注意Boolean.TYPE和Boolean.class的區別,是不一樣的。

 

3.一個很重要的區別。

爲了使用類,須要通過三個步驟:

  1. 加載: 這是由類的加載器執行的。該步驟將查找字節碼,並從這些字節碼中建立一個Class對象。

  2. 連接: 在連接階段將驗證類中的字節碼,爲靜態域分配存儲空間,而且若是必要的話,將解析這個類建立的對其餘類的全部引用。

  3. 初始化: 若是該類具備超類,則對其初始化,執行靜態初始化器和靜態初始化塊。

forName()這種方式會徹底通過這三步。可是".class"方式,第三步會延遲,延遲到對靜態方法或者很是數靜態域進行首次引用時才執行,請看下面的代碼:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
package bells;
 
import java.util.Random;
 
/**
 * @author bells
 *
 */
public class TestClassInitialization {
 
    public static Random rand =new Random(47);
 
    /**
     * @param args
     */
    public static void main(String[] args)throws Exception {
 
        Class initable = Initable.class;
        System.out.println("After creating Initable ref");
        System.out.println(Initable.staticFinal); //這裏Initable的static塊不會被初始化,由於staticFinal是編譯器常量
        System.out.println(Initable.staticFinal2);
 
        System.out.println(Initable2.staticNonFinal);
 
        Class initable3 = Class.forName("typeinfo.Initable3");
        System.out.println("After creating Initable3 ref");
        System.out.println(Initable3.staticNonFinal);
 
    }
 
}
 
class Initable {
    static final int staticFinal =47;
    static final int staticFinal2 = TestClassInitialization.rand.nextInt(1000);
    static {
        System.out.println("Initializing Initable");
    }
}
 
class Initable2 {
    static int staticNonFinal =147;
    static {
        System.out.println("Initaialzing Initable2");
    }
}
 
class Initable3 {
    static int staticNonFinal =74;
    static {
        System.out.println("Initializing Initable3");
    }
}

  運行結果以下:

從結果中能夠看到,僅僅使用.class語法來得到對類的引用不會引發初始化。可是Class.forName()會當即進行初始化。

還有一點:若是一個static final值是「編譯期常量」,就像Initable.staticFinal那樣,則這個值不須要對Initable類進行初始化就能夠被讀取。記住必定要是編譯期常量才行。

相關文章
相關標籤/搜索