咱们都知道Java的反射机制中有三种获取类对象的方式,那么这几种方式的区别究竟是什么呢?
一、new Object().getClass 二、Object.class 三、Class.forName("java.util.String")
由于类对象与类的加载息息相关,因此为了展现区别,咱们先加入动态的和静态的代码块。
public class CalBean { static { System.out.println("静态的代码块。"); } { System.out.println("动态的代码块。"); } public CalBean() { System.out.println("构造方法"); } private Integer num1; private Integer num2; public Integer getNum1() { return num1; } public void setNum1(Integer num1) { this.num1 = num1; } public Integer getNum2() { return num2; } public void setNum2(Integer num2) { this.num2 = num2; } }
建立一个测试单元:java
@SuppressWarnings("unused") @org.junit.Test public void test() { Class<CalBean> cla1 = CalBean.class; System.out.println("==================================="); try { Class<?> cla2 =Class.forName("com.zking.entity.CalBean"); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("==================================="); Class<? extends CalBean> cla3 = new CalBean().getClass(); }
控制台结果:数据结构
结果能够看到,类名.class的方式并未执行该类的代码块或者是代码。
而forName的方式执行了该类的静态代码块。
实例对象.getClass()的方式打印全部内容的缘由显而易见,由于要先实例化。测试
咱们将.class方式与实例对象.getClass()组合测试:this
@SuppressWarnings("unused") @org.junit.Test public void test() { Class<CalBean> cla1 = CalBean.class; System.out.println("==================================="); Class<? extends CalBean> cla3 = new CalBean().getClass(); }
控制台结果:spa
能够看到.class方式仍然没有输出,实例对象.getClass()方式将全部的内容打印。code
这里,咱们测试一下三种方式获取到的类对象是否相等:对象
@SuppressWarnings("unused") @org.junit.Test public void test() { try { Class<CalBean> cla1 = CalBean.class; System.out.println("==================================="); Class<?> cla2 =Class.forName("com.zking.entity.CalBean"); System.out.println("==================================="); Class<? extends CalBean> cla3 = new CalBean().getClass(); System.out.println(cla1 == cla2); System.out.println(cla2 == cla3); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } }
等于号判断引用地址:blog
三种方式获取到的是同一个对象,为何呢?
这就涉及到类的加载过程,咱们知道类加载过程分:加载阶段、链接阶段和初始化阶段。
类的加载阶段是将class文件中的二进制数据读取到内存中,而后将该字节流所表明的静态存储结构转化为方法区中运行时的数据结构,而且在堆内存中生成一个该类的java.lang.class对象,做为方法区数据结构的入口。
类加载阶段的最终产物是堆内存中的class对象,对于同一个Classloader对象,无论某个类被加载多少次,对应堆内存中的class对象始终只有一个。
也就是说不管经过哪一种形式来获取Class对象,得到的都是堆内存中对应的Class对象。