获取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类进行初始化就能够被读取。记住必定要是编译期常量才行。

相关文章
相关标签/搜索