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

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)初始化: 如果该类存在超类,则对其初始化,执行静态初始化器和静态初始化块;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值