您的位置:首页 > 其它

获得Class对象的两种方式比较

2016-04-04 11:20 525 查看
java提供了两种方式来生成对Class对象的引用:

方式1:Class clazz = Class.forName("类的全限定名");

方式2:Class clazz = 类名.class;

两者最大的区别:

(1):方式1是饿汉式加载,而方式2是懒汉式加载的,也就是说在调用方式1这句代码时,该类中的所有static类型变量或者static块都将会加载;但是调用方式2这句代码并不会默认加载所有的static变量或者static块,我们必须手动让他加载;

(2):方式1在找不到要加载类的时候会抛出ClassNotFound异常;而方式2是在编译期间进行检查的,不需要放入try语句块中,因此更加安全,此外他根除了对forName方法的调用,因此相对来说更加高效;

下面用代码来观察两者的区别:

方式1:

package com.hzw.day31;

public class GetClass {
public static void main(String[] args) {
try {
Class clazz = Class.forName("com.hzw.day31.Test");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
class Test
{
public static int age = 23;
public static final String name = "shanxi";
static
{
System.out.println("Test static block");
}
}
输出结果是:

Test static block

可以看到的首先输出的是static 代码块中的内容,表明使用Class.forName()方式会将所有static变量和static块加载进去,即使你不用;

方式2:

public class GetClass {
public static void main(String[] args) {
Class clazz = Test.class;
}
}
class Test
{
public static int age = 23;
public static final String name = "shanxi";
static
{
System.out.println("Test static block");
}
}
输出结果是:

可以发现并没有输出任何结果,这也就证明了方式2是懒汉式加载的,他的初始化操作被延迟到了对静态方法的首次调用才执行;

如果一个static final是"编译器常量"的话,那么这个值也不需要初始化类也能加载进去的,比如下面的例子:

public class GetClass {
public static void main(String[] args) {
System.out.println(Test.name);//①
System.out.println(Test.score);//②
System.out.println(Test.age);//③
}
}
class Test
{
public static int age = 23;
public static final String name = "shanxi";
public static final Integer score = 85;
static
{
System.out.println("Test static block");
}
}


单独运行①输出的结果是: shanxi

单独运行②输出的结果是:

Test static block

85

单独运行③输出的结果是:

Test static block

23

可以看出虽然两者都是static final 类型的,但是name作为"编译常量",他是不需要对类Test进行初始化就可以读取,因而不会执行Test中的静态代码块;但是score虽然作为static final变量,但是他并不是"编译常量",需要初始化Test类之后才可以,因而会首先执行static代码块,随后输出score的值;对于非final的static域,那么对他访问之前要先进行链接(为这个域初始化空间)和初始化(初始化该存储空间),也就明白了单独运行③会首先输出static块的值原因;

补充:

对于采用.class方式来创建对Class对象的引用时,不会自动的初始化该Class对象,为了使用这样的类实际的准备工作包括下面三步:

(1)加载: 这个是由类加载器完成的,该步骤将查找字节码,并利用这些字节码创建一个Class对象;

(2)链接: 在链接阶段将验证类中的字节码,为静态域分配存储空间,如果有必要将解析这个类创建的对其他类的所有引用;

(3)初始化: 如果该类存在超类,则对其初始化,执行静态初始化器和静态初始化块;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: